diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index d26302f4f..831057941 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -2773,15 +2773,68 @@ class Account( suspend fun saveDMRelayList(dmRelays: List) = sendLiterallyEverywhere(dmRelayList.saveRelayList(dmRelays)) - suspend fun saveKeyPackageRelayList(keyPackageRelays: List) = sendLiterallyEverywhere(keyPackageRelayList.saveRelayList(keyPackageRelays)) + suspend fun saveKeyPackageRelayList(keyPackageRelays: List) { + val oldRelays = keyPackageRelayList.flow.value + val newRelays = keyPackageRelays.toSet() + sendLiterallyEverywhere(keyPackageRelayList.saveRelayList(keyPackageRelays)) + if (oldRelays != newRelays) { + republishEventsTo(myKeyPackageEvents(), newRelays) + } + } - suspend fun savePrivateOutboxRelayList(relays: List) = sendMyPublicAndPrivateOutbox(privateStorageRelayList.saveRelayList(relays)) + suspend fun savePrivateOutboxRelayList(relays: List) { + val oldRelays = privateStorageRelayList.flow.value + val newRelays = relays.toSet() + sendMyPublicAndPrivateOutbox(privateStorageRelayList.saveRelayList(relays)) + if (oldRelays != newRelays) { + republishEventsTo(accountSettingsEvents(), newRelays) + } + } - suspend fun saveSearchRelayList(searchRelays: List) = sendMyPublicAndPrivateOutbox(searchRelayList.saveRelayList(searchRelays)) + suspend fun saveSearchRelayList(searchRelays: List) { + val oldRelays = searchRelayList.flowNoDefaults.value + val newRelays = searchRelays.toSet() + sendMyPublicAndPrivateOutbox(searchRelayList.saveRelayList(searchRelays)) + if (oldRelays != newRelays) { + republishEventsTo( + listOfNotNull(userMetadata.getUserMetadataEvent()), + newRelays, + ) + } + } - suspend fun saveIndexerRelayList(trustedRelays: List) = sendMyPublicAndPrivateOutbox(indexerRelayList.saveRelayList(trustedRelays)) + suspend fun saveIndexerRelayList(trustedRelays: List) { + val oldRelays = indexerRelayList.flowNoDefaults.value + val newRelays = trustedRelays.toSet() + sendMyPublicAndPrivateOutbox(indexerRelayList.saveRelayList(trustedRelays)) + if (oldRelays != newRelays) { + republishEventsTo( + listOfNotNull( + userMetadata.getUserMetadataEvent(), + kind3FollowList.getFollowListEvent(), + ), + newRelays, + ) + } + } - suspend fun saveBroadcastRelayList(trustedRelays: List) = sendMyPublicAndPrivateOutbox(broadcastRelayList.saveRelayList(trustedRelays)) + suspend fun saveBroadcastRelayList(trustedRelays: List) { + val oldRelays = broadcastRelayList.flow.value + val newRelays = trustedRelays.toSet() + sendMyPublicAndPrivateOutbox(broadcastRelayList.saveRelayList(trustedRelays)) + if (oldRelays != newRelays) { + republishEventsTo(accountSettingsEvents(), newRelays) + } + } + + suspend fun saveLocalRelayList(relays: List) { + val oldRelays = localRelayList.flow.value + val newRelays = relays.toSet() + localRelayList.saveRelayList(relays) {} + if (oldRelays != newRelays) { + republishEventsTo(accountSettingsEvents(), newRelays) + } + } suspend fun saveProxyRelayList(trustedRelays: List) = sendMyPublicAndPrivateOutbox(proxyRelayList.saveRelayList(trustedRelays)) @@ -2795,6 +2848,53 @@ class Account( suspend fun saveBlockedRelayList(blockedRelays: List) = sendMyPublicAndPrivateOutbox(blockedRelayList.saveRelayList(blockedRelays)) + /** + * Returns all known signed replaceable events that configure this account + * (profile, contact list, relay lists, mute list, bookmarks, etc.). Events + * that have never been created or downloaded are omitted. + */ + fun accountSettingsEvents(): List = + listOfNotNull( + userMetadata.getUserMetadataEvent(), + userMetadata.getExternalIdentitiesEvent(), + kind3FollowList.getFollowListEvent(), + nip65RelayList.getNIP65RelayList(), + dmRelayList.getDMRelayList(), + keyPackageRelayList.getKeyPackageRelayList(), + privateStorageRelayList.getPrivateOutboxRelayList(), + searchRelayList.getSearchRelayList(), + trustedRelayList.getTrustedRelayList(), + proxyRelayList.getProxyRelayList(), + broadcastRelayList.getBroadcastRelayList(), + indexerRelayList.getIndexerRelayList(), + relayFeedsList.getRelayFeedsList(), + blockedRelayList.getBlockedRelayList(), + muteList.getMuteList(), + bookmarkState.getBookmarkList(), + pinState.getPinList(), + blossomServers.getBlossomServersList(), + paymentTargetsState.getPaymentTargetsEvent(), + trustProviderList.getTrustProviderList(), + cache.getAddressableNoteIfExists(appSpecific.getAppSpecificDataAddress())?.event, + ) + + /** + * Returns all currently-known signed KeyPackage events authored by this account. + */ + fun myKeyPackageEvents(): List = + cache.addressables + .filter(KeyPackageEvent.KIND, signer.pubKey) + .mapNotNull { it.event } + + /** Publishes the given events to each of the given relays. No-op if either list is empty. */ + fun republishEventsTo( + events: List, + relays: Set, + ) { + if (relays.isEmpty() || events.isEmpty()) return + events.forEach { client.publish(it, relays) } + } + suspend fun requestToVanish( relays: List, reason: String, @@ -2820,7 +2920,24 @@ class Account( client.publish(signedEvent, followPlusAllMineWithIndex.flow.value + client.availableRelaysFlow().value) } - suspend fun sendNip65RelayList(relays: List) = sendLiterallyEverywhere(nip65RelayList.saveRelayList(relays)) + suspend fun sendNip65RelayList(relays: List) { + val oldOutbox = nip65RelayList.outboxFlowNoDefaults.value + val oldInbox = nip65RelayList.inboxFlowNoDefaults.value + val newOutbox = + relays + .filter { it.type.isWrite() } + .map { it.relayUrl } + .toSet() + val newInbox = + relays + .filter { it.type.isRead() } + .map { it.relayUrl } + .toSet() + sendLiterallyEverywhere(nip65RelayList.saveRelayList(relays)) + if (oldOutbox != newOutbox || oldInbox != newInbox) { + republishEventsTo(accountSettingsEvents(), newOutbox) + } + } suspend fun sendBlossomServersList(servers: List) = sendMyPublicAndPrivateOutbox(blossomServers.saveBlossomServersList(servers)) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListViewModel.kt index aa518d2f0..0a4df4eef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/local/LocalRelayListViewModel.kt @@ -31,6 +31,6 @@ class LocalRelayListViewModel : BasicRelaySetupInfoModel() { .toList() override suspend fun saveRelayList(urlList: List) { - account.localRelayList.saveRelayList(urlList) {} + account.saveLocalRelayList(urlList) } }