Merge pull request #1968 from vitorpamplona/claude/relay-info-nip66-GpWzf
Add relay monitor discovery events display to relay info screen
This commit is contained in:
+3
@@ -39,6 +39,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.hashtag.datasource.HashtagF
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.home.datasource.HomeFilterAssembler
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.datasource.UserProfileFilterAssembler
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relay.datasource.RelayFeedFilterAssembler
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource.RelayInfoNip66FilterAssembler
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.threadview.datasources.ThreadFilterAssembler
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource.VideoFilterAssembler
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
@@ -80,6 +81,7 @@ class RelaySubscriptionsCoordinator(
|
||||
val hashtags = HashtagFilterAssembler(client)
|
||||
val geohashes = GeoHashFilterAssembler(client)
|
||||
val relayFeed = RelayFeedFilterAssembler(client)
|
||||
val relayInfoNip66 = RelayInfoNip66FilterAssembler(client)
|
||||
val followPacks = FollowPackFeedFilterAssembler(client)
|
||||
val chess = ChessFilterAssembler(client)
|
||||
|
||||
@@ -105,6 +107,7 @@ class RelaySubscriptionsCoordinator(
|
||||
hashtags,
|
||||
geohashes,
|
||||
relayFeed,
|
||||
relayInfoNip66,
|
||||
chess,
|
||||
nwc,
|
||||
)
|
||||
|
||||
+220
-31
@@ -62,7 +62,6 @@ import androidx.compose.material.icons.filled.Language
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material.icons.filled.Payment
|
||||
import androidx.compose.material.icons.filled.PrivacyTip
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Storage
|
||||
import androidx.compose.material.icons.filled.Tag
|
||||
import androidx.compose.material.icons.filled.Topic
|
||||
@@ -81,7 +80,9 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -118,6 +119,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.BackButton
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource.RelayInfoNip66FilterAssemblerSubscription
|
||||
import com.vitorpamplona.amethyst.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
|
||||
import com.vitorpamplona.amethyst.ui.theme.Height25Modifier
|
||||
@@ -255,7 +257,6 @@ import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListEvent
|
||||
import com.vitorpamplona.quartz.nip75ZapGoals.GoalEvent
|
||||
import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataEvent
|
||||
import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent
|
||||
import com.vitorpamplona.quartz.nip86RelayManagement.Nip86Client
|
||||
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
|
||||
import com.vitorpamplona.quartz.nip88Polls.response.PollResponseEvent
|
||||
import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent
|
||||
@@ -328,8 +329,12 @@ fun RelayInformationScreen(
|
||||
)
|
||||
},
|
||||
) { pad ->
|
||||
RelayInfoNip66FilterAssemblerSubscription(relay, accountViewModel)
|
||||
|
||||
val relayInfo by loadRelayInfo(relay)
|
||||
|
||||
val discoveryEvents by loadRelayDiscoveryEvents(relay)
|
||||
|
||||
val messages =
|
||||
remember(relay) {
|
||||
Amethyst.instance.relayStats
|
||||
@@ -341,7 +346,7 @@ fun RelayInformationScreen(
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
RelayInformationBody(relay, relayInfo, Amethyst.instance.relayStats.get(relay), messages, pad, accountViewModel, nav)
|
||||
RelayInformationBody(relay, relayInfo, discoveryEvents, Amethyst.instance.relayStats.get(relay), messages, pad, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +354,7 @@ fun RelayInformationScreen(
|
||||
fun RelayInformationBody(
|
||||
relay: NormalizedRelayUrl,
|
||||
relayInfo: Nip11RelayInformation,
|
||||
discoveryEvents: ImmutableList<RelayDiscoveryEvent>,
|
||||
relayStats: RelayStat,
|
||||
messages: ImmutableList<IRelayDebugMessage>,
|
||||
pad: PaddingValues,
|
||||
@@ -428,6 +434,13 @@ fun RelayInformationBody(
|
||||
item { SoftwareCard(relayInfo) }
|
||||
}
|
||||
|
||||
if (discoveryEvents.isNotEmpty()) {
|
||||
item { SectionHeader(stringRes(R.string.relay_monitor_reports)) }
|
||||
items(discoveryEvents, key = { it.id }) { event ->
|
||||
RelayMonitorReportCard(event, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
if (usedBy.isNotEmpty()) {
|
||||
item {
|
||||
SectionHeader(stringRes(R.string.used_by))
|
||||
@@ -528,7 +541,7 @@ fun RelayInformationBody(
|
||||
// Active subscriptions + outbox display
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fun kindDisplayName(kind: Int): Int =
|
||||
private fun kindDisplayName(kind: Int): Int =
|
||||
when (kind) {
|
||||
AdvertisedRelayListEvent.KIND -> R.string.kind_outbox_relays
|
||||
AppDefinitionEvent.KIND -> R.string.kind_apps
|
||||
@@ -1105,35 +1118,18 @@ private fun RelayHeader(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Row(
|
||||
OutlinedButton(
|
||||
modifier = Modifier.padding(horizontal = 30.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
shape = ButtonBorder,
|
||||
onClick = { nav.nav(Route.RelayFeed(url = relay.url)) },
|
||||
) {
|
||||
OutlinedButton(
|
||||
shape = ButtonBorder,
|
||||
onClick = { nav.nav(Route.RelayFeed(url = relay.url)) },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.Feed,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(18.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(text = stringRes(R.string.see_relay_feed))
|
||||
}
|
||||
|
||||
if (Nip86Client.supportsNip86(relayInfo.supported_nips)) {
|
||||
OutlinedButton(
|
||||
onClick = { nav.nav(Route.RelayManagement(relay.url)) },
|
||||
shape = ButtonBorder,
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Settings,
|
||||
contentDescription = stringRes(R.string.manage),
|
||||
modifier = Height25Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.Feed,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(18.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(text = stringRes(R.string.see_relay_feed))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1554,6 +1550,198 @@ fun PoliciesCard(relay: Nip11RelayInformation) {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun loadRelayDiscoveryEvents(relay: NormalizedRelayUrl): State<ImmutableList<RelayDiscoveryEvent>> =
|
||||
produceState<ImmutableList<RelayDiscoveryEvent>>(persistentListOf(), relay) {
|
||||
LocalCache
|
||||
.observeEvents(
|
||||
Filter(
|
||||
kinds = listOf(RelayDiscoveryEvent.KIND),
|
||||
tags = mapOf("d" to listOf(relay.url)),
|
||||
),
|
||||
).collect { events ->
|
||||
value =
|
||||
events
|
||||
.filterIsInstance<RelayDiscoveryEvent>()
|
||||
.sortedByDescending { it.createdAt }
|
||||
.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RelayMonitorReportCard(
|
||||
event: RelayDiscoveryEvent,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
OutlinedCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
// Monitor author + timestamp
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
LoadUser(baseUserHex = event.pubKey, accountViewModel) { user ->
|
||||
if (user != null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
UserPicture(
|
||||
user = user,
|
||||
size = Size25dp,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
UserCompose(
|
||||
baseUser = user,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = timeAgoNoDot(event.createdAt, context),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
// RTT metrics
|
||||
val rttOpen = event.rttOpen()
|
||||
val rttRead = event.rttRead()
|
||||
val rttWrite = event.rttWrite()
|
||||
|
||||
if (rttOpen != null || rttRead != null || rttWrite != null) {
|
||||
Text(
|
||||
stringRes(R.string.relay_monitor_rtt),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
) {
|
||||
rttOpen?.let {
|
||||
RttChip(stringRes(R.string.relay_monitor_rtt_open), it)
|
||||
}
|
||||
rttRead?.let {
|
||||
RttChip(stringRes(R.string.relay_monitor_rtt_read), it)
|
||||
}
|
||||
rttWrite?.let {
|
||||
RttChip(stringRes(R.string.relay_monitor_rtt_write), it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Network type
|
||||
val networkTypes = event.networkTypes()
|
||||
if (networkTypes.isNotEmpty()) {
|
||||
InfoRow(
|
||||
Icons.Default.Language,
|
||||
stringRes(R.string.relay_monitor_network),
|
||||
networkTypes.joinToString { it.code },
|
||||
)
|
||||
}
|
||||
|
||||
// Relay type
|
||||
val relayTypes = event.relayTypes()
|
||||
if (relayTypes.isNotEmpty()) {
|
||||
InfoRow(
|
||||
Icons.Default.Dns,
|
||||
stringRes(R.string.relay_monitor_relay_type),
|
||||
relayTypes.joinToString(),
|
||||
)
|
||||
}
|
||||
|
||||
// Supported NIPs
|
||||
val supportedNips = event.supportedNips()
|
||||
if (supportedNips.isNotEmpty()) {
|
||||
Text(
|
||||
stringRes(R.string.relay_monitor_supported_nips),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
val uri = LocalUriHandler.current
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
supportedNips.forEach { nip ->
|
||||
val nipStr = nip.toString().padStart(2, '0')
|
||||
SuggestionChip(
|
||||
onClick = {
|
||||
runCatching {
|
||||
uri.openUri(nipLink(nipStr))
|
||||
}
|
||||
},
|
||||
label = { Text(nipStr) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Requirements
|
||||
val requirements = event.requirements()
|
||||
if (requirements.isNotEmpty()) {
|
||||
InfoRow(
|
||||
Icons.Default.Lock,
|
||||
stringRes(R.string.relay_monitor_requirements),
|
||||
requirements.joinToString { req ->
|
||||
if (req.negated) "!${req.value}" else req.value
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RttChip(
|
||||
label: String,
|
||||
ms: Long,
|
||||
) {
|
||||
val color =
|
||||
when {
|
||||
ms < 200 -> Color(0xFF4CAF50)
|
||||
|
||||
// green
|
||||
ms < 500 -> Color(0xFFFFC107)
|
||||
|
||||
// amber
|
||||
else -> MaterialTheme.colorScheme.error
|
||||
}
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
Surface(
|
||||
shape = RoundedCornerShape(50),
|
||||
color = color.copy(alpha = 0.15f),
|
||||
) {
|
||||
Text(
|
||||
text = stringRes(R.string.relay_monitor_ms, ms.toInt()),
|
||||
modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = color,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SectionHeader(title: String) {
|
||||
Text(
|
||||
@@ -1678,6 +1866,7 @@ fun RelayHeaderPreview() {
|
||||
),
|
||||
supported_grasps = listOf("GRASP-01"),
|
||||
),
|
||||
discoveryEvents = persistentListOf(),
|
||||
pad = PaddingValues(0.dp),
|
||||
relayStats = RelayStat(),
|
||||
messages =
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManager
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
class RelayInfoNip66QueryState(
|
||||
val relayUrl: NormalizedRelayUrl,
|
||||
val relays: Set<NormalizedRelayUrl>,
|
||||
)
|
||||
|
||||
class RelayInfoNip66FilterAssembler(
|
||||
client: INostrClient,
|
||||
) : ComposeSubscriptionManager<RelayInfoNip66QueryState>() {
|
||||
val group =
|
||||
listOf(
|
||||
RelayInfoNip66FilterSubAssembler(client, ::allKeys),
|
||||
)
|
||||
|
||||
override fun invalidateKeys() = invalidateFilters()
|
||||
|
||||
override fun invalidateFilters() = group.forEach { it.invalidateFilters() }
|
||||
|
||||
override fun destroy() = group.forEach { it.destroy() }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import com.vitorpamplona.amethyst.commons.relayClient.subscriptions.KeyDataSourceSubscription
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
@Composable
|
||||
fun RelayInfoNip66FilterAssemblerSubscription(
|
||||
relayUrl: NormalizedRelayUrl,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
val state =
|
||||
remember(relayUrl) {
|
||||
RelayInfoNip66QueryState(relayUrl, accountViewModel.account.followOutboxesOrProxy.flow.value)
|
||||
}
|
||||
|
||||
KeyDataSourceSubscription(state, accountViewModel.dataSources().relayInfoNip66)
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.datasource
|
||||
|
||||
import com.vitorpamplona.amethyst.service.relayClient.eoseManagers.PerUniqueIdEoseManager
|
||||
import com.vitorpamplona.amethyst.service.relays.SincePerRelayMap
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip66RelayMonitor.discovery.RelayDiscoveryEvent
|
||||
|
||||
class RelayInfoNip66FilterSubAssembler(
|
||||
client: INostrClient,
|
||||
allKeys: () -> Set<RelayInfoNip66QueryState>,
|
||||
) : PerUniqueIdEoseManager<RelayInfoNip66QueryState, String>(client, allKeys) {
|
||||
override fun updateFilter(
|
||||
key: RelayInfoNip66QueryState,
|
||||
since: SincePerRelayMap?,
|
||||
): List<RelayBasedFilter> {
|
||||
val relayUrl = key.relayUrl.url
|
||||
|
||||
return key.relays.map { relay ->
|
||||
RelayBasedFilter(
|
||||
relay = relay,
|
||||
filter =
|
||||
Filter(
|
||||
kinds = listOf(RelayDiscoveryEvent.KIND),
|
||||
tags = mapOf("d" to listOf(relayUrl)),
|
||||
limit = 20,
|
||||
since = since?.get(relay)?.time,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun id(key: RelayInfoNip66QueryState) = key.relayUrl.url
|
||||
}
|
||||
@@ -418,10 +418,6 @@
|
||||
<string name="remove_from_private_bookmarks">Remove from Private Bookmarks</string>
|
||||
<string name="remove_from_public_bookmarks">Remove from Public Bookmarks</string>
|
||||
|
||||
<string name="pinned_notes">Pinned Notes</string>
|
||||
<string name="pin_to_profile">Pin to Profile</string>
|
||||
<string name="unpin_from_profile">Unpin from Profile</string>
|
||||
|
||||
<string name="bookmark_lists">Bookmark Lists</string>
|
||||
<string name="bookmark_list_icon_label">Icon for bookmark list</string>
|
||||
<string name="bookmark_list_creation_screen_title">New Bookmark List</string>
|
||||
@@ -827,6 +823,17 @@
|
||||
<string name="terms_and_conditions">Terms & Conditions</string>
|
||||
<string name="not_available_acronym">N/A</string>
|
||||
<string name="relay_error_messages">Errors and Notices from this Relay</string>
|
||||
<string name="relay_monitor_reports">Relay Monitor Reports</string>
|
||||
<string name="relay_monitor_rtt_open">Open</string>
|
||||
<string name="relay_monitor_rtt_read">Read</string>
|
||||
<string name="relay_monitor_rtt_write">Write</string>
|
||||
<string name="relay_monitor_rtt">RTT</string>
|
||||
<string name="relay_monitor_network">Network</string>
|
||||
<string name="relay_monitor_relay_type">Type</string>
|
||||
<string name="relay_monitor_supported_nips">Supported NIPs</string>
|
||||
<string name="relay_monitor_requirements">Requirements</string>
|
||||
<string name="relay_monitor_last_check">Last check</string>
|
||||
<string name="relay_monitor_ms">%1$d ms</string>
|
||||
<string name="relay_active_subscriptions">Active Subscriptions</string>
|
||||
<string name="relay_active_outbox">Pending Outbox Events</string>
|
||||
<string name="relay_req_subscriptions">REQ Subscriptions (%1$d)</string>
|
||||
@@ -1974,97 +1981,4 @@
|
||||
<string name="web_bookmark_delete">Delete</string>
|
||||
<string name="web_bookmark_delete_confirm">Delete this web bookmark?</string>
|
||||
<string name="web_bookmark_open_url">Open URL</string>
|
||||
|
||||
<!-- NIP-75 Zap Goals -->
|
||||
<string name="goal_closed">This goal has closed</string>
|
||||
<string name="goal_progress">%1$s funded of %2$s sats goal</string>
|
||||
<string name="goal_amount_label">Goal amount (sats)</string>
|
||||
<string name="goal_amount_placeholder">100000</string>
|
||||
<string name="goal_description_label">Describe your goal</string>
|
||||
<string name="goal_description_placeholder">What are you fundraising for?</string>
|
||||
<string name="goal_summary_label">Short summary</string>
|
||||
<string name="goal_summary_placeholder">Brief description shown in previews</string>
|
||||
<string name="goal_image_label">Image URL (optional)</string>
|
||||
<string name="goal_image_placeholder">https://example.com/image.jpg</string>
|
||||
<string name="goal_website_label">Website URL (optional)</string>
|
||||
<string name="goal_website_placeholder">https://example.com</string>
|
||||
<string name="goal_deadline_label">Deadline (optional)</string>
|
||||
<string name="goal_set_deadline">Set a deadline</string>
|
||||
<string name="new_goal">New Goal</string>
|
||||
<string name="goal_create">Create Goal</string>
|
||||
<string name="request_to_vanish">Request to Vanish</string>
|
||||
<string name="request_to_vanish_description">Request relays to permanently delete all your data up to the selected date. This action is based on NIP-62 and is legally binding in some jurisdictions.</string>
|
||||
<string name="vanish_select_relay">Select a relay</string>
|
||||
<string name="vanish_target_relay">Target Relays</string>
|
||||
<string name="vanish_all_relays">ALL RELAYS</string>
|
||||
<string name="vanish_all_relays_warning">This will request ALL relays to delete everything associated with your key up to the selected date. This event will be broadcast as widely as possible. This action cannot be undone.</string>
|
||||
<string name="vanish_date_label">Delete data up to</string>
|
||||
<string name="vanish_date_explainer">All your events created before this date will be requested for deletion from the selected relay.</string>
|
||||
<string name="vanish_reason_label">Reason (optional)</string>
|
||||
<string name="vanish_reason_placeholder">Reason or legal notice for the relay operator</string>
|
||||
<string name="vanish_send_request">Send Vanish Request</string>
|
||||
<string name="vanish_confirm_title">Confirm Vanish Request</string>
|
||||
<string name="vanish_confirm_single_relay">You are about to request %1$s to permanently delete all your data created before the selected date. This cannot be undone.</string>
|
||||
<string name="vanish_confirm_all_relays">You are about to request EVERY relay to permanently delete all your data created before the selected date. This will be broadcast everywhere and cannot be undone.</string>
|
||||
<string name="vanish_request_sent">Vanish request sent</string>
|
||||
<string name="vanish_select_date">Select date</string>
|
||||
<string name="vanish_select_time">Select time</string>
|
||||
|
||||
<string name="vanish_events_title">Vanish History</string>
|
||||
<string name="vanish_events_refresh">Refresh</string>
|
||||
<string name="vanish_events_description">These are your past Request to Vanish events found on connected relays. Relays tagged in these events should not hold any of your data from before the event date.</string>
|
||||
<string name="vanish_events_empty">No vanish requests found</string>
|
||||
<string name="vanish_events_empty_hint">You haven\'t sent any Request to Vanish events yet.</string>
|
||||
<string name="vanish_target_relays_label">Target Relays</string>
|
||||
<string name="vanish_all_relays_compliance_hint">This request targets all relays. Use the Request to Vanish screen to test specific relays for compliance.</string>
|
||||
<string name="vanish_test_button">Test</string>
|
||||
<string name="vanish_compliant">Compliant</string>
|
||||
<string name="vanish_non_compliant">Non-compliant</string>
|
||||
<string name="vanish_test_error">Error</string>
|
||||
<string name="vanish_history">Vanish History</string>
|
||||
<!-- NIP-86 Relay Management -->
|
||||
<string name="relay_management_title">Manage %1$s</string>
|
||||
<string name="relay_management_loading">Loading relay management capabilities…</string>
|
||||
<string name="relay_management_error">Unable to connect to relay management</string>
|
||||
<string name="relay_management_no_methods">No management methods available</string>
|
||||
<string name="relay_management_dismiss">Dismiss</string>
|
||||
<string name="relay_management_tab_pubkeys">Users</string>
|
||||
<string name="relay_management_tab_events">Events</string>
|
||||
<string name="relay_management_tab_kinds">Kinds</string>
|
||||
<string name="relay_management_tab_ips">IPs</string>
|
||||
<string name="relay_management_tab_settings">Settings</string>
|
||||
<string name="relay_management_banned_pubkeys">Banned Users</string>
|
||||
<string name="relay_management_no_banned_pubkeys">No banned users</string>
|
||||
<string name="relay_management_allowed_pubkeys">Allowed Users</string>
|
||||
<string name="relay_management_no_allowed_pubkeys">No allowed users</string>
|
||||
<string name="relay_management_moderation_queue">Moderation Queue</string>
|
||||
<string name="relay_management_no_moderation_events">No events needing moderation</string>
|
||||
<string name="relay_management_banned_events">Banned Events</string>
|
||||
<string name="relay_management_no_banned_events">No banned events</string>
|
||||
<string name="relay_management_allowed_kinds">Allowed Kinds</string>
|
||||
<string name="relay_management_no_allowed_kinds">No allowed kinds</string>
|
||||
<string name="relay_management_blocked_ips">Blocked IPs</string>
|
||||
<string name="relay_management_no_blocked_ips">No blocked IPs</string>
|
||||
<string name="relay_management_add">Add</string>
|
||||
<string name="relay_management_remove">Remove</string>
|
||||
<string name="relay_management_allow">Allow</string>
|
||||
<string name="relay_management_ban">Ban</string>
|
||||
<string name="relay_management_ban_pubkey">Ban Pubkey</string>
|
||||
<string name="relay_management_allow_pubkey">Allow Pubkey</string>
|
||||
<string name="relay_management_ban_event">Ban Event</string>
|
||||
<string name="relay_management_allow_kind">Allow Kind</string>
|
||||
<string name="relay_management_block_ip">Block IP</string>
|
||||
<string name="relay_management_pubkey_hex">Pubkey (hex)</string>
|
||||
<string name="relay_management_event_id_hex">Event ID (hex)</string>
|
||||
<string name="relay_management_kind_number">Kind number</string>
|
||||
<string name="relay_management_ip_address">IP address</string>
|
||||
<string name="relay_management_reason_optional">Reason (optional)</string>
|
||||
<string name="relay_management_confirm">Confirm</string>
|
||||
<string name="relay_management_cancel">Cancel</string>
|
||||
<string name="relay_management_apply">Apply</string>
|
||||
<string name="relay_management_relay_name">Relay Name</string>
|
||||
<string name="relay_management_relay_description">Relay Description</string>
|
||||
<string name="relay_management_relay_icon_url">Relay Icon URL</string>
|
||||
<string name="relay_management_button">Manage Relay</string>
|
||||
<string name="manage">Manage</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user