diff --git a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt index 3aebe1c1c..a5f447e65 100644 --- a/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt +++ b/amethyst/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt @@ -80,7 +80,7 @@ class ImageUploadTesting { .addInterceptor(DefaultContentTypeInterceptor("Amethyst/${BuildConfig.VERSION_NAME}")) .build() - private suspend fun getBitmap(): ByteArray { + private fun getBitmap(): ByteArray { val bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.ARGB_8888) for (x in 0 until bitmap.width) { for (y in 0 until bitmap.height) { @@ -127,7 +127,7 @@ class ImageUploadTesting { // assertEquals(server.baseUrl, "${server.baseUrl}/$initialHash", result.url?.removeSuffix(".png")) val imageData: ByteArray = - ImageDownloader().waitAndGetImage(result.url!!, { client })?.bytes + ImageDownloader().waitAndGetImage(result.url!!) { client }?.bytes ?: run { fail("${server.name}: Should not be null") return @@ -142,8 +142,7 @@ class ImageUploadTesting { ServerInfoRetriever() .loadInfo( server.baseUrl, - { client }, - ) + ) { client } val payload = getBitmap() val inputStream = payload.inputStream() @@ -172,7 +171,7 @@ class ImageUploadTesting { Assert.assertTrue("${server.name}: Invalid result url", url.startsWith("http")) val imageData: ByteArray = - ImageDownloader().waitAndGetImage(url, { client })?.bytes + ImageDownloader().waitAndGetImage(url) { client }?.bytes ?: run { fail("${server.name}: Should not be null") return diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt index c05fa392c..7856ab8b2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt @@ -147,12 +147,14 @@ class AppModules( // Custom fetcher that considers tor settings and avoids forwarding. val nip05Fetcher = OkHttpNip05Fetcher(roleBasedHttpClientBuilder::okHttpClientForNip05) + val namecoinElectrumxClient = + ElectrumXClient( + socketFactory = { roleBasedHttpClientBuilder.socketFactoryForNip05() }, + ) + val namecoinResolver = NamecoinNameResolver( - electrumxClient = - ElectrumXClient( - socketFactory = { roleBasedHttpClientBuilder.socketFactoryForNip05() }, - ), + electrumxClient = namecoinElectrumxClient, serverListProvider = { if (roleBasedHttpClientBuilder.shouldUseTorForNIP05("https://electrumx.example.com")) { TOR_ELECTRUMX_SERVERS @@ -226,7 +228,7 @@ class AppModules( val relayStats = RelayStats(client) // Logs debug messages when needed - val detailedLogger = if (isDebug) RelayLogger(client, false, false) else null + val detailedLogger = if (isDebug) RelayLogger(client, debugSending = false, debugReceiving = false) else null val relayReqStats = if (isDebug) RelayReqStats(client) else null val logger = if (isDebug) RelaySpeedLogger(client) else null 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 3b65d75b5..f394fec57 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -1240,7 +1240,7 @@ class Account( val event = signer.sign(template) cache.justConsumeMyOwnEvent(event) val relays = relayList(event) - if (relays != null && relays.isNotEmpty()) { + if (!relays.isNullOrEmpty()) { client.send(event, relays.toSet()) } else { client.send(event, computeRelayListToBroadcast(event)) @@ -1898,7 +1898,7 @@ class Account( fun getRelevantReports(note: Note): Set { val innerReports = if (note.event is RepostEvent || note.event is GenericRepostEvent) { - note.replyTo?.map { getRelevantReports(it) }?.flatten() ?: emptyList() + note.replyTo?.flatMap { getRelevantReports(it) } ?: emptyList() } else { emptyList() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt index 94c178cd6..a2c42cc88 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AccountSettings.kt @@ -186,8 +186,8 @@ class AccountSettings( var backupEphemeralChatList: EphemeralChatListEvent? = null, var backupTrustProviderList: TrustProviderListEvent? = null, val lastReadPerRoute: MutableStateFlow>> = MutableStateFlow(mapOf()), - val hasDonatedInVersion: MutableStateFlow> = MutableStateFlow(setOf()), - val pendingAttestations: MutableStateFlow> = MutableStateFlow>(mapOf()), + val hasDonatedInVersion: MutableStateFlow> = MutableStateFlow(setOf()), + val pendingAttestations: MutableStateFlow> = MutableStateFlow(mapOf()), var backupNipA3PaymentTargets: PaymentTargetsEvent? = null, ) : EphemeralChatRepository, PublicChatListRepository { @@ -612,7 +612,7 @@ class AccountSettings( route: String, timestampInSecs: Long, ): MutableStateFlow = - MutableStateFlow(timestampInSecs).also { newFlow -> + MutableStateFlow(timestampInSecs).also { newFlow -> lastReadPerRoute.update { it + Pair(route, newFlow) } saveAccountSettings() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt index 2d21b2b66..75c9e3aa7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/AntiSpamFilter.kt @@ -170,7 +170,7 @@ class AntiSpamFilter { } } - val flowSpam = MutableStateFlow(AntiSpamState(this)) + val flowSpam = MutableStateFlow(AntiSpamState(this)) } class AntiSpamState( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt index c9a61d5cc..bc7c6cce3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LargeSoftCache.kt @@ -25,14 +25,13 @@ import java.lang.ref.WeakReference import java.util.concurrent.ConcurrentSkipListMap import java.util.function.BiConsumer -class LargeSoftCache : CacheOperations { - protected val cache = ConcurrentSkipListMap>() +class LargeSoftCache : CacheOperations { + private val cache = ConcurrentSkipListMap>() fun keys() = cache.keys fun get(key: K): V? { - val softRef = cache.get(key) - if (softRef == null) return null + val softRef = cache.get(key) ?: return null val value = softRef.get() return if (value != null) { @@ -99,7 +98,7 @@ class LargeSoftCache : CacheOperations { // another thread may put in between cache.remove(key, softRef) val newObject = builder(key) - return cache.putIfAbsent(key, WeakReference(newObject))?.get() ?: newObject + cache.putIfAbsent(key, WeakReference(newObject))?.get() ?: newObject } } } @@ -135,7 +134,7 @@ class LargeSoftCache : CacheOperations { .forEach(BiConsumerWrapper(this, consumer)) } - class BiConsumerWrapper( + class BiConsumerWrapper( val cache: LargeSoftCache, val inner: BiConsumer, ) : BiConsumer> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 0f637f3ed..7e8a21219 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -2770,10 +2770,9 @@ object LocalCache : ILocalCache, ICacheProvider { val childrenToBeRemoved = mutableListOf() val toBeRemoved = - account.hiddenUsers.flow.value.hiddenUsers - .map { userHex -> - (notes.filter { _, it -> it.event?.pubKey == userHex } + addressables.filter { _, it -> it.event?.pubKey == userHex }).toSet() - }.flatten() + account.hiddenUsers.flow.value.hiddenUsers.flatMap { userHex -> + (notes.filter { _, it -> it.event?.pubKey == userHex } + addressables.filter { _, it -> it.event?.pubKey == userHex }).toSet() + } toBeRemoved.forEach { removeFromCache(it) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt index b0c01c92a..d075edd0a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip03Timestamp/TorAwareOkHttpOtsResolverBuilder.kt @@ -34,9 +34,9 @@ class TorAwareOkHttpOtsResolverBuilder( ) : OtsResolverBuilder { fun getAPI(usingTor: Boolean) = if (usingTor) { - OkHttpBitcoinExplorer.Companion.MEMPOOL_API_URL + OkHttpBitcoinExplorer.MEMPOOL_API_URL } else { - OkHttpBitcoinExplorer.Companion.BLOCKSTREAM_API_URL + OkHttpBitcoinExplorer.BLOCKSTREAM_API_URL } override fun build(): OtsResolver = @@ -44,9 +44,9 @@ class TorAwareOkHttpOtsResolverBuilder( explorer = OkHttpBitcoinExplorer( baseUrl = { - getAPI(usingTor = isTorActive(OkHttpBitcoinExplorer.Companion.MEMPOOL_API_URL)) + getAPI(usingTor = isTorActive(OkHttpBitcoinExplorer.MEMPOOL_API_URL)) }, - client = okHttpClient(OkHttpBitcoinExplorer.Companion.MEMPOOL_API_URL), + client = okHttpClient(OkHttpBitcoinExplorer.MEMPOOL_API_URL), cache = cache, ), calendar = OkHttpCalendar(okHttpClient), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/BookmarkListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/BookmarkListState.kt index ca15f42c4..9a438a880 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/BookmarkListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/BookmarkListState.kt @@ -62,7 +62,7 @@ class BookmarkListState( fun getBookmarkList(): BookmarkListEvent? = bookmarkList.event as? BookmarkListEvent - suspend fun publicBookmarks(note: Note): List { + fun publicBookmarks(note: Note): List { val noteEvent = note.event as? BookmarkListEvent return noteEvent?.publicBookmarks() ?: emptyList() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt index c39699277..8f45d8534 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/HiddenUsersState.kt @@ -47,7 +47,7 @@ class HiddenUsersState( ) { var transientHiddenUsers: MutableStateFlow> = MutableStateFlow(setOf()) - suspend fun assembleLiveHiddenUsers( + fun assembleLiveHiddenUsers( blockList: List, muteList: List, transientHiddenUsers: Set, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/labeledBookmarkLists/LabeledBookmarkList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/labeledBookmarkLists/LabeledBookmarkList.kt index fc82eb262..8a16f79bd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/labeledBookmarkLists/LabeledBookmarkList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/labeledBookmarkLists/LabeledBookmarkList.kt @@ -34,9 +34,9 @@ data class LabeledBookmarkList( val privateBookmarks: Set = emptySet(), val publicBookmarks: Set = emptySet(), ) { - val privatePostBookmarks = privateBookmarks.filter { it is EventBookmark }.map { bookmarkIdTag -> bookmarkIdTag as EventBookmark } - val publicPostBookmarks = publicBookmarks.filter { it is EventBookmark }.map { bookmarkIdTag -> bookmarkIdTag as EventBookmark } + val privatePostBookmarks = privateBookmarks.filterIsInstance() + val publicPostBookmarks = publicBookmarks.filterIsInstance() - val privateArticleBookmarks = privateBookmarks.filter { it is AddressBookmark }.map { bookmarkIdTag -> bookmarkIdTag as AddressBookmark } - val publicArticleBookmarks = publicBookmarks.filter { it is AddressBookmark }.map { bookmarkIdTag -> bookmarkIdTag as AddressBookmark } + val privateArticleBookmarks = privateBookmarks.filterIsInstance() + val publicArticleBookmarks = publicBookmarks.filterIsInstance() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt index e382bdfdd..1f823adbc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/searchRelays/SearchRelayListState.kt @@ -51,7 +51,7 @@ class SearchRelayListState( // Creates a long-term reference for this note so that the GC doesn't collect the note it self val searchListNote = cache.getOrCreateAddressableNote(getSearchRelayListAddress()) - fun getSearchRelayListAddress() = SearchRelayListEvent.Companion.createAddress(signer.pubKey) + fun getSearchRelayListAddress() = SearchRelayListEvent.createAddress(signer.pubKey) fun getSearchRelayListFlow(): StateFlow = searchListNote.flow().metadata.stateFlow @@ -70,7 +70,7 @@ class SearchRelayListState( .flowOn(Dispatchers.IO) .stateIn( scope, - SharingStarted.Companion.Eagerly, + SharingStarted.Eagerly, emptySet(), ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt index 11eef7564..995c41cd6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip51Lists/trustedRelays/TrustedRelayListState.kt @@ -68,7 +68,7 @@ class TrustedRelayListState( .flowOn(Dispatchers.IO) .stateIn( scope, - SharingStarted.Companion.Eagerly, + SharingStarted.Eagerly, emptySet(), ) @@ -76,13 +76,13 @@ class TrustedRelayListState( val relayListForTrusted = getTrustedRelayList() return if (relayListForTrusted != null && relayListForTrusted.tags.isNotEmpty()) { - TrustedRelayListEvent.Companion.updateRelayList( + TrustedRelayListEvent.updateRelayList( earlierVersion = relayListForTrusted, relays = trustedRelays, signer = signer, ) } else { - TrustedRelayListEvent.Companion.create( + TrustedRelayListEvent.create( relays = trustedRelays, signer = signer, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt index 735868c78..ca4fbc387 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nipB7Blossom/BlossomServerListState.kt @@ -120,5 +120,5 @@ class BlossomServerListState( suspend fun createBlossomDeleteAuth( hash: HexKey, alt: String, - ): BlossomAuthorizationEvent? = BlossomAuthorizationEvent.createDeleteAuth(hash, alt, signer) + ): BlossomAuthorizationEvent = BlossomAuthorizationEvent.createDeleteAuth(hash, alt, signer) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/DataStoreExt.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/DataStoreExt.kt index f66037979..6c6611192 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/DataStoreExt.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/DataStoreExt.kt @@ -29,13 +29,13 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.map import java.io.IOException -suspend fun DataStore.getProperty( +fun DataStore.getProperty( key: Preferences.Key, parser: (String) -> T, serializer: (T) -> String, scope: CoroutineScope, ): UpdatablePropertyFlow = - UpdatablePropertyFlow( + UpdatablePropertyFlow( flow = data .catch { e -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt index 6ec67ae1a..02498472a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/preferences/EncryptedDataStore.kt @@ -67,12 +67,12 @@ class EncryptedDataStore( ?.get(key) ?.let { decrypt(it) } - suspend fun getProperty( + fun getProperty( key: Preferences.Key, parser: (String) -> T, serializer: (T) -> String, ): UpdatablePropertyFlow = - UpdatablePropertyFlow( + UpdatablePropertyFlow( flow = store.data .catch { e -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt index dba3ca53d..f3d7ae385 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/serverList/MergedFollowListsState.kt @@ -60,8 +60,8 @@ class MergedFollowListsState( val geotags: Set = emptySet(), val communities: Set = emptySet(), ) { - val geotagScopes: Set = geotags.mapTo(mutableSetOf()) { GeohashId.toScope(it) } - val hashtagScopes: Set = hashtags.mapTo(mutableSetOf()) { HashtagId.toScope(it) } + val geotagScopes: Set = geotags.mapTo(mutableSetOf()) { GeohashId.toScope(it) } + val hashtagScopes: Set = hashtags.mapTo(mutableSetOf()) { HashtagId.toScope(it) } } fun mergeLists( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/OutboxLoaderState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/OutboxLoaderState.kt index 49bf8371c..708731655 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/OutboxLoaderState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/OutboxLoaderState.kt @@ -48,7 +48,7 @@ class OutboxLoaderState( }.flowOn(Dispatchers.IO) .stateIn( scope, - SharingStarted.Companion.Eagerly, + SharingStarted.Eagerly, UnknownTopNavPerRelayFilterSet, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt index a607a0d42..6386b1d4d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByOutboxTopNavFilter.kt @@ -52,8 +52,8 @@ class AllFollowsByOutboxTopNavFilter( val defaultRelays: StateFlow>, val blockedRelays: StateFlow>, ) : IFeedTopNavFilter { - val geotagScopes: Set? = geotags?.mapTo(mutableSetOf()) { GeohashId.Companion.toScope(it) } - val hashtagScopes: Set? = hashtags?.mapTo(mutableSetOf()) { HashtagId.Companion.toScope(it) } + val geotagScopes: Set? = geotags?.mapTo(mutableSetOf()) { GeohashId.toScope(it) } + val hashtagScopes: Set? = hashtags?.mapTo(mutableSetOf()) { HashtagId.toScope(it) } override fun matchAuthor(pubkey: HexKey): Boolean = authors == null || pubkey in authors diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt index edd06abd5..bed71c9b8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsByProxyTopNavFilter.kt @@ -47,8 +47,8 @@ class AllFollowsByProxyTopNavFilter( val communities: Set? = null, val proxyRelays: Set, ) : IFeedTopNavFilter { - val geotagScopes: Set? = geotags?.mapTo(mutableSetOf()) { GeohashId.Companion.toScope(it) } - val hashtagScopes: Set? = hashtags?.mapTo(mutableSetOf()) { HashtagId.Companion.toScope(it) } + val geotagScopes: Set? = geotags?.mapTo(mutableSetOf()) { GeohashId.toScope(it) } + val hashtagScopes: Set? = hashtags?.mapTo(mutableSetOf()) { HashtagId.toScope(it) } override fun matchAuthor(pubkey: HexKey): Boolean = authors == null || pubkey in authors diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsTopNavPerRelayFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsTopNavPerRelayFilter.kt index ff670117e..443bfd5c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsTopNavPerRelayFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/allFollows/AllFollowsTopNavPerRelayFilter.kt @@ -35,6 +35,6 @@ class AllFollowsTopNavPerRelayFilter( val geotags: Set? = null, val communities: Set? = null, ) : IFeedTopNavPerRelayFilter { - val geotagScopes: Set? = geotags?.mapTo(mutableSetOf()) { GeohashId.toScope(it) } - val hashtagScopes: Set? = hashtags?.mapTo(mutableSetOf()) { HashtagId.toScope(it) } + val geotagScopes: Set? = geotags?.mapTo(mutableSetOf()) { GeohashId.toScope(it) } + val hashtagScopes: Set? = hashtags?.mapTo(mutableSetOf()) { HashtagId.toScope(it) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavFilter.kt index 7f0284b1c..24b39bee6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavFilter.kt @@ -37,7 +37,7 @@ class LocationTopNavFilter( val geotags: Set, val relayList: Set, ) : IFeedTopNavFilter { - val geotagScopes: Set = geotags.mapTo(mutableSetOf()) { GeohashId.toScope(it) } + val geotagScopes: Set = geotags.mapTo(mutableSetOf()) { GeohashId.toScope(it) } override fun matchAuthor(pubkey: HexKey): Boolean = true diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavPerRelayFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavPerRelayFilter.kt index 4792a92b2..bd1cd0743 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavPerRelayFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/aroundMe/LocationTopNavPerRelayFilter.kt @@ -28,5 +28,5 @@ import com.vitorpamplona.quartz.nip73ExternalIds.location.GeohashId class LocationTopNavPerRelayFilter( val geotags: Set, ) : IFeedTopNavPerRelayFilter { - val geotagScopes: Set = geotags.mapTo(mutableSetOf()) { GeohashId.toScope(it) } + val geotagScopes: Set = geotags.mapTo(mutableSetOf()) { GeohashId.toScope(it) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/NoteFeedFlow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/NoteFeedFlow.kt index a32aabae3..fbd5492b2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/NoteFeedFlow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/topNavFeeds/noteBased/NoteFeedFlow.kt @@ -62,7 +62,7 @@ class NoteFeedFlow( ): IFeedTopNavFilter = when (noteEvent) { is PeopleListEvent -> { - if (noteEvent.dTag() == PeopleListEvent.Companion.BLOCK_LIST_D_TAG) { + if (noteEvent.dTag() == PeopleListEvent.BLOCK_LIST_D_TAG) { MutedAuthorsByOutboxTopNavFilter(caches.peopleListCache.cachedUserIdSet(noteEvent), blockedRelays) } else { AuthorsByOutboxTopNavFilter(caches.peopleListCache.cachedUserIdSet(noteEvent), blockedRelays) @@ -109,7 +109,7 @@ class NoteFeedFlow( ) { when (noteEvent) { is PeopleListEvent -> { - if (noteEvent.dTag() == PeopleListEvent.Companion.BLOCK_LIST_D_TAG) { + if (noteEvent.dTag() == PeopleListEvent.BLOCK_LIST_D_TAG) { emit(MutedAuthorsByOutboxTopNavFilter(caches.peopleListCache.userIdSet(noteEvent), blockedRelays)) } else { emit(AuthorsByOutboxTopNavFilter(caches.peopleListCache.userIdSet(noteEvent), blockedRelays)) @@ -161,7 +161,7 @@ class NoteFeedFlow( ): IFeedTopNavFilter = when (noteEvent) { is PeopleListEvent -> { - if (noteEvent.dTag() == PeopleListEvent.Companion.BLOCK_LIST_D_TAG) { + if (noteEvent.dTag() == PeopleListEvent.BLOCK_LIST_D_TAG) { MutedAuthorsByProxyTopNavFilter(caches.peopleListCache.cachedUserIdSet(noteEvent), proxyRelays) } else { AuthorsByProxyTopNavFilter(caches.peopleListCache.cachedUserIdSet(noteEvent), proxyRelays) @@ -208,7 +208,7 @@ class NoteFeedFlow( ) { when (noteEvent) { is PeopleListEvent -> { - if (noteEvent.dTag() == PeopleListEvent.Companion.BLOCK_LIST_D_TAG) { + if (noteEvent.dTag() == PeopleListEvent.BLOCK_LIST_D_TAG) { emit(MutedAuthorsByProxyTopNavFilter(caches.peopleListCache.userIdSet(noteEvent), proxyRelays)) } else { emit(AuthorsByProxyTopNavFilter(caches.peopleListCache.userIdSet(noteEvent), proxyRelays)) @@ -272,7 +272,7 @@ class NoteFeedFlow( override fun startValue(): IFeedTopNavFilter { val noteEvent = metadataFlow.value?.note?.event return if (noteEvent == null) { - return AuthorsByOutboxTopNavFilter(emptySet(), blockedRelays) + AuthorsByOutboxTopNavFilter(emptySet(), blockedRelays) } else { if (proxyRelays.value.isEmpty()) { processByOutbox(noteEvent, outboxRelays.value) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt index d12b1ea08..6ea4f28bf 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/cashu/melt/MeltProcessor.kt @@ -83,7 +83,7 @@ class MeltProcessor { ) } - suspend fun melt( + fun melt( token: CashuToken, lud16: String, okHttpClient: (String) -> OkHttpClient, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt index 925209294..c2ebbb38a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/eventCache/MemoryTrimmingService.kt @@ -32,7 +32,7 @@ class MemoryTrimmingService( ) { var isTrimmingMemoryMutex = AtomicBoolean(false) - private suspend fun doTrim( + private fun doTrim( account: Collection, otherAccounts: List, ) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index 5f3da6350..da9cc9ae5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -65,14 +65,11 @@ class LightningAddressResolver { okHttpClient: (String) -> OkHttpClient, context: Context, ): String { - val url = assembleUrl(lnAddress) - - if (url == null) { - throw LightningAddressError( + val url = + assembleUrl(lnAddress) ?: throw LightningAddressError( stringRes(context, R.string.error_unable_to_fetch_invoice), stringRes(context, R.string.could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup, lnAddress), ) - } val client = okHttpClient(url) @@ -126,12 +123,14 @@ class LightningAddressResolver { okHttpClient: (String) -> OkHttpClient, context: Context, ): String { + @Suppress("BlockingMethodInNonBlockingContext") // URLEncoder.encode is CPU-only, not I/O blocking val encodedMessage = URLEncoder.encode(message, "utf-8") val urlBinder = if (lnCallback.contains("?")) "&" else "?" var url = "$lnCallback${urlBinder}amount=$milliSats&comment=$encodedMessage" if (nostrRequest != null) { + @Suppress("BlockingMethodInNonBlockingContext") // URLEncoder.encode is CPU-only, not I/O blocking val encodedNostrRequest = URLEncoder.encode(nostrRequest.toJson(), "utf-8") url += "&nostr=$encodedNostrRequest" } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt index 5e432c61e..c72cd8fe9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/location/LocationState.kt @@ -55,7 +55,7 @@ class LocationState( object Loading : LocationResult() } - private var hasLocationPermission = MutableStateFlow(false) + private var hasLocationPermission = MutableStateFlow(false) private var latestLocation: LocationResult = LocationResult.Loading fun setLocationPermission(newValue: Boolean) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/namecoin/NamecoinNameService.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/namecoin/NamecoinNameService.kt index 7f4bf2c37..d2240151b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/namecoin/NamecoinNameService.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/namecoin/NamecoinNameService.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.service.namecoin +import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.DEFAULT_ELECTRUMX_SERVERS import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumXClient import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.ElectrumxServer import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinLookupCache @@ -43,12 +44,17 @@ class NamecoinNameService( ) { private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) - private val resolver = NamecoinNameResolver(electrumxClient) - private val cache = NamecoinLookupCache() - // Custom server list (user-configurable) + @Volatile private var customServers: List = emptyList() + private val resolver = + NamecoinNameResolver( + electrumxClient = electrumxClient, + serverListProvider = { customServers.ifEmpty { DEFAULT_ELECTRUMX_SERVERS } }, + ) + private val cache = NamecoinLookupCache() + // ── Public API ───────────────────────────────────────────────────── /** @@ -97,7 +103,10 @@ class NamecoinNameService( * * Useful for composable UIs that observe resolution state. */ - fun resolveLive(identifier: String): StateFlow { + fun resolveLive( + identifier: String, + scope: CoroutineScope = this.scope, + ): StateFlow { val state = MutableStateFlow(NamecoinResolveState.Loading) scope.launch { try { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpDebugLogging.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpDebugLogging.kt index 367627357..e3c48929d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpDebugLogging.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpDebugLogging.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service.okhttp import okhttp3.internal.concurrent.TaskRunner import okhttp3.internal.http2.Http2 import java.io.Closeable +import java.util.Locale import java.util.concurrent.CopyOnWriteArraySet import java.util.logging.ConsoleHandler import java.util.logging.Handler @@ -45,7 +46,7 @@ object OkHttpDebugLogging { level = Level.FINE formatter = object : SimpleFormatter() { - override fun format(record: LogRecord) = String.format("[%1\$tF %1\$tT] %2\$s %n", record.millis, record.message) + override fun format(record: LogRecord) = String.format(Locale.ROOT, $$"[%1$tF %1$tT] %2$s %n", record.millis, record.message) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpWebSocket.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpWebSocket.kt index 146d532e8..9f2ad864a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpWebSocket.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/okhttp/OkHttpWebSocket.kt @@ -48,8 +48,7 @@ class OkHttpWebSocket( override fun needsReconnect(): Boolean { if (socket == null) return true - val myUsingOkHttp = usingOkHttp - if (myUsingOkHttp == null) return true + val myUsingOkHttp = usingOkHttp ?: return true val currentOkHttp = httpClient(url) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt index f7e31c162..20ddfc233 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt @@ -102,7 +102,7 @@ fun VideoView( ) { val automaticallyStartPlayback = remember { - mutableStateOf( + mutableStateOf( if (alwaysShowVideo) true else accountViewModel.settings.startVideoPlayback(), ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt index 68e285b64..cef95667c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt @@ -30,7 +30,7 @@ import com.vitorpamplona.amethyst.service.playback.composable.mainVideo.VideoPla import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.GetMediaItem import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -public val DEFAULT_MUTED_SETTING = mutableStateOf(true) +val DEFAULT_MUTED_SETTING = mutableStateOf(true) @Composable fun VideoViewInner( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/MuteButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/MuteButton.kt index 0fe24ca92..e33a001dd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/MuteButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/MuteButton.kt @@ -76,7 +76,7 @@ fun MuteButton( ) { val holdOn = remember { - mutableStateOf( + mutableStateOf( true, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt index 145d8e9dc..a98c8232c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/IntentExtras.kt @@ -77,7 +77,7 @@ class IntentExtras { data.mimeType?.let { putString("mimeType", it) } data.aspectRatio?.let { putFloat("aspectRatio", it) } data.proxyPort?.let { putInt("proxyPort", it) } - data.keepPlaying.let { putBoolean("keepPlaying", it) } + putBoolean("keepPlaying", data.keepPlaying) data.waveformData?.let { putFloatArray("wavefrontData", it.wave.toFloatArray()) } bounds?.let { putInt("boundLeft", it.left) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt index 765138b3e..4a01cb6ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/pip/PipVideoView.kt @@ -20,8 +20,6 @@ */ package com.vitorpamplona.amethyst.service.playback.pip -import android.content.Context.RECEIVER_EXPORTED -import android.os.Build import androidx.annotation.OptIn import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -34,6 +32,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.core.content.ContextCompat import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.ContentFrame import androidx.media3.ui.compose.state.rememberMuteButtonState @@ -91,13 +90,8 @@ fun RegisterControllerReceiver(controllerState: MediaControllerState) { onPlayPause = controllerState::togglePlayPause, ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - context.registerReceiver(receiver, receiver.filterMute, RECEIVER_EXPORTED) - context.registerReceiver(receiver, receiver.filterPlayPause, RECEIVER_EXPORTED) - } else { - context.registerReceiver(receiver, receiver.filterMute) - context.registerReceiver(receiver, receiver.filterPlayPause) - } + ContextCompat.registerReceiver(context, receiver, receiver.filterMute, ContextCompat.RECEIVER_EXPORTED) + ContextCompat.registerReceiver(context, receiver, receiver.filterPlayPause, ContextCompat.RECEIVER_EXPORTED) onDispose { context.unregisterReceiver(receiver) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt index 65a0d433b..665530fc0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/playerPool/ExoPlayerBuilder.kt @@ -35,7 +35,7 @@ import okhttp3.OkHttpClient class ExoPlayerBuilder( val okHttp: OkHttpClient, ) { - fun build(context: Context) = + fun build(context: Context): ExoPlayer = ExoPlayer .Builder(context) .apply { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/ListWithUniqueSetCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/ListWithUniqueSetCache.kt index ec84d87dd..c48bc6a6b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/ListWithUniqueSetCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/authCommand/model/ListWithUniqueSetCache.kt @@ -26,7 +26,7 @@ class ListWithUniqueSetCache( val key: (T) -> U, ) { private val list = AtomicReference(listOf()) - private val cacheSet = AtomicReference?>(setOf()) + private val cacheSet = AtomicReference?>(setOf()) fun isEmpty() = list.get().isEmpty() @@ -41,7 +41,7 @@ class ListWithUniqueSetCache( } fun distinct(): Set { - var currentSet = cacheSet.get() + val currentSet = cacheSet.get() // Check if the cached set is based on the current list if (currentSet != null) { @@ -49,7 +49,7 @@ class ListWithUniqueSetCache( } // Compute and attempt to atomically update the cache - val newSet = list.get().mapTo(mutableSetOf(), key) + val newSet = list.get().mapTo(mutableSetOf(), key) cacheSet.compareAndSet(currentSet, newSet) return newSet } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt index bc00b34b9..6798df8ac 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/RelaySubscriptionsCoordinator.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.service.relayClient.reqCommand -import com.vitorpamplona.amethyst.commons.relayClient.composeSubscriptionManagers.ComposeSubscriptionManagerControls import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.AccountFilterAssembler import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.ChannelFinderFilterAssemblyGroup @@ -88,7 +87,7 @@ class RelaySubscriptionsCoordinator( val nwc = NWCPaymentFilterAssembler(client) val all = - listOf( + listOf( account, home, chatroomList, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/FilterDraftsAndReportsFromKey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/FilterDraftsAndReportsFromKey.kt index 08cbe1654..e4525e953 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/FilterDraftsAndReportsFromKey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/drafts/FilterDraftsAndReportsFromKey.kt @@ -36,7 +36,7 @@ fun filterDraftsFromKey( pubkey: HexKey?, since: Long?, ): List { - if (pubkey == null || pubkey.isEmpty()) return emptyList() + if (pubkey.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt index eb23bfe13..8192abf20 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/AccountFollowsLoaderSubAssembler.kt @@ -72,7 +72,7 @@ class AccountFollowsLoaderSubAssembler( * This assembler saves the EOSE per user key. That EOSE includes their metadata, etc * and reports, but only from trusted accounts (follows of all logged in users). */ - val hasTried: EOSEAccountFast = EOSEAccountFast(2000) + val hasTried: EOSEAccountFast = EOSEAccountFast(2000) // updates all filters override fun invalidateFilters(ignoreIfDoing: Boolean) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt index efbc76b80..4db9ea1e5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/follows/FilterFindFollowMetadataForKey.kt @@ -92,7 +92,7 @@ fun pickRelaysToLoadUsers( val outbox = key.authorRelayList()?.writeRelaysNorm() - if (outbox != null && outbox.isNotEmpty()) { + if (!outbox.isNullOrEmpty()) { // If there is a home, get from it. // if it tried all outbox relays, stop. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBasicAccountInfoFromKeys.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBasicAccountInfoFromKeys.kt index 6d78b6a09..f680b4c0a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBasicAccountInfoFromKeys.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBasicAccountInfoFromKeys.kt @@ -70,7 +70,7 @@ fun filterBasicAccountInfoFromKeys( otherAccounts: List?, since: Long?, ): List { - if (otherAccounts == null || otherAccounts.isEmpty()) return emptyList() + if (otherAccounts.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBookmarksAndReportsFromKey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBookmarksAndReportsFromKey.kt index 4ede695a3..cc8ebc0b8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBookmarksAndReportsFromKey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/metadata/FilterBookmarksAndReportsFromKey.kt @@ -38,7 +38,7 @@ fun filterBookmarksAndReportsFromKey( pubkey: HexKey?, since: Long?, ): List { - if (pubkey == null || pubkey.isEmpty()) return emptyList() + if (pubkey.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt index f3e594d31..9d7c0cdfe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt @@ -49,7 +49,7 @@ class AccountNotificationsEoseFromInboxRelaysManager( override fun updateFilter( key: AccountQueryState, since: SincePerRelayMap?, - ): List? = + ): List = key.account.notificationRelays.flow.value.flatMap { filterSummaryNotificationsToPubkey( relay = it, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt index 55c14ab57..9aa0acc87 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt @@ -50,7 +50,7 @@ class AccountNotificationsEoseFromRandomRelaysManager( override fun updateFilter( key: AccountQueryState, since: SincePerRelayMap?, - ): List? { + ): List { // only loads this after the feed is built val defaultSince = key.feedContentStates.notifications.lastNoteCreatedAtIfFilled() ?: TimeUtils.oneWeekAgo() return (key.account.followsPerRelay.value.keys - key.account.notificationRelays.flow.value).flatMap { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt index 02c02efc3..bf7c6659f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/FilterNotificationsToPubkey.kt @@ -90,7 +90,7 @@ fun filterSummaryNotificationsToPubkey( pubkey: HexKey?, since: Long?, ): List { - if (pubkey == null || pubkey.isEmpty()) return emptyList() + if (pubkey.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( @@ -111,7 +111,7 @@ fun filterNotificationsToPubkey( pubkey: HexKey?, since: Long?, ): List { - if (pubkey == null || pubkey.isEmpty()) return emptyList() + if (pubkey.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( @@ -142,7 +142,7 @@ fun filterJustTheLatestNotificationsToPubkeyFromRandomRelays( pubkey: HexKey?, since: Long?, ): List { - if (pubkey == null || pubkey.isEmpty()) return emptyList() + if (pubkey.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/FilterGiftWrapsToPubkey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/FilterGiftWrapsToPubkey.kt index 03481eeae..081f2e486 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/FilterGiftWrapsToPubkey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip59GiftWraps/FilterGiftWrapsToPubkey.kt @@ -32,7 +32,7 @@ fun filterGiftWrapsToPubkey( pubkey: HexKey?, since: Long?, ): List { - if (pubkey == null || pubkey.isEmpty()) return emptyList() + if (pubkey.isNullOrEmpty()) return emptyList() return listOf( RelayBasedFilter( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt index a2da47ae6..c14d14bd1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/channel/nip28PublicChats/ChannelLoaderSubAssembler.kt @@ -38,7 +38,7 @@ class ChannelLoaderSubAssembler( client: INostrClient, allKeys: () -> Set, ) : SingleSubNoEoseCacheEoseManager(client, allKeys, invalidateAfterEose = true) { - override fun updateFilter(keys: List): List? = filterMissingChannelsById(keys) + override fun updateFilter(keys: List): List = filterMissingChannelsById(keys) override fun distinct(key: ChannelFinderQueryState) = key.channel } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt index 616465f9a..251cf0fa2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingAddressables.kt @@ -40,7 +40,7 @@ fun potentialRelaysToFindAddress(note: AddressableNote): Set LocalCache.getAnyChannel(note)?.relays()?.let { set.addAll(it) } - note.replyTo?.map { parentNote -> + note.replyTo?.forEach { parentNote -> set.addAll(parentNote.relays) LocalCache.getAnyChannel(parentNote)?.relays()?.let { set.addAll(it) } @@ -48,7 +48,7 @@ fun potentialRelaysToFindAddress(note: AddressableNote): Set parentNote.author?.inboxRelays()?.let { set.addAll(it) } } - note.replies.map { childNote -> + note.replies.forEach { childNote -> set.addAll(childNote.relays) LocalCache.getAnyChannel(childNote)?.relays()?.let { set.addAll(it) } @@ -63,7 +63,7 @@ fun potentialRelaysToFindAddress(note: AddressableNote): Set } } - note.boosts.map { childNote -> + note.boosts.forEach { childNote -> set.addAll(childNote.relays) childNote.author?.outboxRelays()?.let { set.addAll(it) } } @@ -71,7 +71,7 @@ fun potentialRelaysToFindAddress(note: AddressableNote): Set return set } -fun filterMissingAddressables(keys: List): List? { +fun filterMissingAddressables(keys: List): List { val addressesPerRelay = mapOfSet { keys.forEach { key -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingEvents.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingEvents.kt index c3a8da9c0..1506da482 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingEvents.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/loaders/FilterMissingEvents.kt @@ -36,7 +36,7 @@ fun potentialRelaysToFindEvent(note: Note): Set { LocalCache.getAnyChannel(note)?.relays()?.let { set.addAll(it) } - note.replyTo?.map { parentNote -> + note.replyTo?.forEach { parentNote -> set.addAll(parentNote.relays) LocalCache.getAnyChannel(parentNote)?.relays()?.let { set.addAll(it) } @@ -44,7 +44,7 @@ fun potentialRelaysToFindEvent(note: Note): Set { parentNote.author?.inboxRelays()?.let { set.addAll(it) } } - note.replies.map { childNote -> + note.replies.forEach { childNote -> set.addAll(childNote.relays) LocalCache.getAnyChannel(childNote)?.relays()?.let { set.addAll(it) } @@ -59,7 +59,7 @@ fun potentialRelaysToFindEvent(note: Note): Set { } } - note.boosts.map { childNote -> + note.boosts.forEach { childNote -> set.addAll(childNote.relays) childNote.author?.outboxRelays()?.let { set.addAll(it) } } @@ -67,7 +67,7 @@ fun potentialRelaysToFindEvent(note: Note): Set { return set } -fun filterMissingEvents(keys: List): List? { +fun filterMissingEvents(keys: List): List { val eventsPerRelay = mapOfSet { keys.forEach { key -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/watchers/EventWatcherSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/watchers/EventWatcherSubAssembler.kt index 2a648f18b..be3e7e252 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/watchers/EventWatcherSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/event/watchers/EventWatcherSubAssembler.kt @@ -37,7 +37,7 @@ class EventWatcherSubAssembler( allKeys: () -> Set, ) : SingleSubEoseManager(client, allKeys) { var lastNotesOnFilter = emptyList() - var latestEOSEs: EOSEAccountFast = EOSEAccountFast(1000) + var latestEOSEs: EOSEAccountFast = EOSEAccountFast(1000) override fun newEose( relay: NormalizedRelayUrl, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/loaders/UserOutboxFinderSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/loaders/UserOutboxFinderSubAssembler.kt index 56c9982e3..44316d6b1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/loaders/UserOutboxFinderSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/loaders/UserOutboxFinderSubAssembler.kt @@ -49,7 +49,7 @@ class UserOutboxFinderSubAssembler( * This assembler saves the EOSE per user key. That EOSE includes their metadata, etc * and reports, but only from trusted accounts (follows of all logged in users). */ - var hasTried: EOSEAccountFast = EOSEAccountFast(200) + var hasTried: EOSEAccountFast = EOSEAccountFast(200) fun newEose( relay: NormalizedRelayUrl, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt index f749ea41d..19474b6c4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserCardsSubAssembler.kt @@ -68,7 +68,7 @@ class UserCardsSubAssembler( val trustedAccounts: Map> = mapOfSet { accounts.forEach { account -> - account.homeRelays.flow.value.map { + account.homeRelays.flow.value.forEach { add(it, account.userProfile().pubkeyHex) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt index 9937eac60..345cbd096 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/speedLogger/KindGroup.kt @@ -30,8 +30,8 @@ import kotlin.concurrent.atomics.ExperimentalAtomicApi class KindGroup( var count: AtomicInteger = AtomicInteger(0), var memory: AtomicInteger = AtomicInteger(0), - val subs: LargeCache = LargeCache(), - val relays: LargeCache = LargeCache(), + val subs: LargeCache = LargeCache(), + val relays: LargeCache = LargeCache(), ) { companion object { const val MB: Int = 1024 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt index c04b6531b..e5e8179c0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relays/EOSE.kt @@ -32,7 +32,7 @@ typealias MutableTime = com.vitorpamplona.amethyst.commons.relays.MutableTime open class EOSEByKey( cacheSize: Int = 200, ) { - var followList: LruCache = LruCache(cacheSize) + var followList: LruCache = LruCache(cacheSize) fun addOrUpdate( listCode: U, @@ -99,7 +99,7 @@ open class EOSEAccountKey( class EOSEAccountFast( cacheSize: Int = 20, ) { - private val users: LruCache = LruCache(cacheSize) + private val users: LruCache = LruCache(cacheSize) private val lock = Any() fun addOrUpdate( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt index 0b9ec7042..c517d75f9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/tts/TextToSpeechEngine.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.service.tts import android.content.Context import android.media.AudioAttributes -import android.os.Build import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener import java.util.Locale @@ -79,15 +78,13 @@ class TextToSpeechEngine private constructor() { engine.setPitch(defaultPitch) engine.setSpeechRate(defaultSpeed) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - val audioAttributes = - AudioAttributes - .Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) - .setUsage(AudioAttributes.USAGE_MEDIA) - .build() - engine.setAudioAttributes(audioAttributes) - } + val audioAttributes = + AudioAttributes + .Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) + .setUsage(AudioAttributes.USAGE_MEDIA) + .build() + engine.setAudioAttributes(audioAttributes) engine.setListener( onStart = { onStartListener?.invoke() }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt index 9f2dc5433..b23559684 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AudioWaveformReadOnly.kt @@ -170,7 +170,7 @@ internal fun Iterable.fillToSize( transform: (List) -> T, ): List { val capacity = ceil(size.safeDiv(count())).roundToInt() - return map { data -> List(capacity) { data } }.flatten().chunkToSize(size, transform) + return flatMap { data -> List(capacity) { data } }.chunkToSize(size, transform) } internal fun Iterable.chunkToSize( @@ -207,6 +207,4 @@ internal fun Iterable.normalize( return values.map { scale * ((it - currentMin) / range) + min } } -private fun Int.safeDiv(value: Int): Float { - return if (value == 0) return 0F else this / value.toFloat() -} +private fun Int.safeDiv(value: Int): Float = if (value == 0) 0F else this / value.toFloat() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt index ad2498aad..125d03248 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRoute.kt @@ -108,7 +108,7 @@ fun LoadOrCreateNote( content: @Composable (Note?) -> Unit, ) { var note by - remember(event.id) { mutableStateOf(accountViewModel.getNoteIfExists(event.id)) } + remember(event.id) { mutableStateOf(accountViewModel.getNoteIfExists(event.id)) } if (note == null) { LaunchedEffect(key1 = event.id) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt index 18b45ffc4..4b7e59b38 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/SensitivityWarning.kt @@ -117,7 +117,7 @@ fun SensitivityWarning( @Composable fun ContentWarningNotePreview() { ThemeComparisonColumn { - ContentWarningNote({}) + ContentWarningNote {} } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt index ba25e3a42..7b53a2fdd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt @@ -49,7 +49,7 @@ class ChannelFeedContentState( val feedContent = _feedContent.asStateFlow() // Simple counter that changes when it needs to invalidate everything - private val _scrollToTop = MutableStateFlow(0) + private val _scrollToTop = MutableStateFlow(0) val scrollToTop = _scrollToTop.asStateFlow() var scrolltoTopPending = false @@ -64,7 +64,7 @@ class ChannelFeedContentState( viewModelScope.launch(Dispatchers.IO) { _scrollToTop.emit(_scrollToTop.value + 1) } } - suspend fun sentToTop() { + fun sentToTop() { scrolltoTopPending = false } @@ -98,10 +98,10 @@ class ChannelFeedContentState( if (notes.isEmpty()) { _feedContent.tryEmit(ChannelFeedState.Empty) } else if (currentState is ChannelFeedState.Loaded) { - currentState.feed.tryEmit(LoadedFeedState(notes, localFilter.showHiddenKey())) + currentState.feed.tryEmit(LoadedFeedState(notes, localFilter.showHiddenKey())) } else { _feedContent.tryEmit( - ChannelFeedState.Loaded(MutableStateFlow(LoadedFeedState(notes, localFilter.showHiddenKey()))), + ChannelFeedState.Loaded(MutableStateFlow(LoadedFeedState(notes, localFilter.showHiddenKey()))), ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingBottomBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingBottomBar.kt index 4972c960f..68281cf55 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingBottomBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingBottomBar.kt @@ -18,7 +18,7 @@ * 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.myapplication +package com.vitorpamplona.amethyst.ui.layouts import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.AnimationState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingFloatingButton.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingFloatingButton.kt index 6cdf473fc..0da9167d3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingFloatingButton.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingFloatingButton.kt @@ -18,7 +18,7 @@ * 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.myapplication +package com.vitorpamplona.amethyst.ui.layouts import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt index 8bb60a28b..3096fb99a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/DisappearingScaffold.kt @@ -32,8 +32,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.DividerThickness -import com.vitorpamplona.myapplication.DisappearingBottomBar -import com.vitorpamplona.myapplication.DisappearingFloatingButton @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt index 4cbd74bfe..9c2dfa282 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/drawer/AccountSwitchBottomSheet.kt @@ -130,7 +130,7 @@ fun DisplayAccount( accountSessionManager: AccountSessionManager, ) { var baseUser by remember(acc) { - mutableStateOf( + mutableStateOf( decodePublicKeyAsHexOrNull(acc.npub)?.let { LocalCache.getUserIfExists(it) }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/navs/Nav.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/navs/Nav.kt index 7956d1e77..f3087a352 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/navs/Nav.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/navs/Nav.kt @@ -87,7 +87,7 @@ class Nav( ) { navigationScope.launch { controller.navigate(route) { - popUpTo(klass) { inclusive = true } + popUpTo(klass) { inclusive = true } } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt index 25bdca7df..1f06f23b0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/routes/RouteMaker.kt @@ -323,7 +323,7 @@ suspend fun routeEditDraftTo( is ChatroomKeyable -> { val room = draft.chatroomKey(account.userProfile().pubkeyHex) account.chatroomList.getOrCreatePrivateChatroom(room) - return Route.Room(room, draftId = note.idHex) + Route.Room(room, draftId = note.idHex) } is TextNoteEvent -> { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt index ebd0913b7..b00c1735a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/BlankNote.kt @@ -98,7 +98,7 @@ fun HiddenNotePreview() { ThemeComparisonColumn( toPreview = { HiddenNote( - reports = persistentSetOf(), + reports = persistentSetOf(), isHiddenAuthor = true, accountViewModel = mockAccountViewModel(), nav = EmptyNav(), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index 281f797ae..c7396dd00 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -167,7 +167,7 @@ fun ObserveAllStatusesToAvoidSwitchigAllTheTime( statuses: ImmutableList, accountViewModel: AccountViewModel, ) { - statuses.map { + statuses.forEach { EventFinderFilterAssemblerSubscription(it, accountViewModel) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 53a400164..14b896c4f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -240,6 +240,7 @@ import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.BaseVoiceEvent import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext @Composable fun NoteCompose( @@ -536,7 +537,7 @@ fun ClickableNote( nav.nav { if (redirectToNote.event is DraftWrapEvent) { - with(Dispatchers.IO) { + withContext(Dispatchers.IO) { routeEditDraftTo(redirectToNote, accountViewModel.account) } } else { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index 85dbd35e2..30ec920a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -481,7 +481,7 @@ private fun ReactionDetailGallery( accountViewModel: AccountViewModel, ) { val defaultBackgroundColor = MaterialTheme.colorScheme.background - val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } + val backgroundColor = remember { mutableStateOf(defaultBackgroundColor) } val hasReactions by observeNoteReferences(baseNote, accountViewModel) @@ -757,7 +757,7 @@ private fun SlidingAnimationCount( if (accountViewModel.settings.isPerformanceMode()) { TextCount(baseCount, textColor) } else { - AnimatedContent( + AnimatedContent( targetState = baseCount, transitionSpec = AnimatedContentTransitionScope::transitionSpec, label = "SlidingAnimationCount", diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt index 1a50d6e23..bf760560e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ReplyInformation.kt @@ -86,8 +86,8 @@ fun ReplyInformationChannel( onUserTagClick: (User) -> Unit, ) { FlowRow { - if (mentions != null && mentions.isNotEmpty()) { - if (replyTo != null && replyTo.isNotEmpty()) { + if (!mentions.isNullOrEmpty()) { + if (!replyTo.isNullOrEmpty()) { Text( stringRes(id = R.string.replying_to), fontSize = 13.sp, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt index 99d2cc893..107bd36aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/TimeAgoFormatter.kt @@ -32,7 +32,7 @@ import kotlin.math.round private const val YEAR_DATE_FORMAT = "MMM dd, yyyy" private const val MONTH_DATE_FORMAT = "MMM dd" -var locale = Locale.getDefault() +var locale: Locale = Locale.getDefault() var yearFormatter = SimpleDateFormat(YEAR_DATE_FORMAT, locale) var monthFormatter = SimpleDateFormat(MONTH_DATE_FORMAT, locale) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt index 8cb381999..9d4b31d4a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapPollNoteViewModel.kt @@ -262,7 +262,7 @@ class PollNoteViewModel : ViewModel() { valueMinimum?.let { minimum -> valueMaximum?.let { maximum -> if (minimum != maximum) { - options.add(((minimum + maximum) / 2).toLong()) + options.add(((minimum + maximum) / 2)) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt index d996b105a..a014a1627 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt @@ -34,9 +34,9 @@ import kotlin.uuid.Uuid @Stable class DraftTagState { var current: String by mutableStateOf(newTag()) - var usedDraftTags by mutableStateOf(setOf(current)) + var usedDraftTags by mutableStateOf(setOf(current)) - private val _versions = MutableStateFlow(0) + private val _versions = MutableStateFlow(0) @OptIn(FlowPreview::class) val versions = _versions.debounce(1000) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt index bf0ad4223..955696d97 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/UserSuggestionState.kt @@ -43,7 +43,7 @@ class UserSuggestionState( val account: Account, val requireAtSymbol: Boolean = true, ) { - val invalidations = MutableStateFlow(0) + val invalidations = MutableStateFlow(0) val currentWord = MutableStateFlow("") val searchDataSourceState = SearchQueryState(MutableStateFlow(""), account) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt index 9ef050b0e..f40ab6d72 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/DisplayZapSplits.kt @@ -51,7 +51,7 @@ fun DisplayZapSplits( remember(noteEvent) { val list = noteEvent.zapSplitSetup() if (list.isEmpty() && useAuthorIfEmpty) { - listOf( + listOf( ZapSplitSetup( pubKeyHex = noteEvent.pubKey, relay = null, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt index a25ef4f8a..54cde53ca 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayReward.kt @@ -116,13 +116,13 @@ private fun RenderPledgeAmount( ) { val repliesState by observeNoteReplies(baseNote, accountViewModel) var reward by remember { - mutableStateOf( + mutableStateOf( showAmount(baseReward.amount), ) } var hasPledge by remember { - mutableStateOf( + mutableStateOf( false, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt index 2038a77b7..c63cd5a5c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayUncitedHashtags.kt @@ -58,7 +58,7 @@ fun DisplayUncitedHashtags( nav: INav, ) { val unusedHashtags by - produceState(initialValue = emptyList()) { + produceState(initialValue = emptyList()) { val tagsInEvent = event.hashtags() if (tagsInEvent.isNotEmpty()) { val state = CachedRichTextParser.parseText(content, event.tags.toImmutableListOfLists(), callbackUri) @@ -66,15 +66,15 @@ fun DisplayUncitedHashtags( val tagsInContent = state .paragraphs - .map { - it.words.mapNotNull { + .flatMap { paragraphState -> + paragraphState.words.mapNotNull { if (it is HashTagSegment) { it.hashtag } else { null } } - }.flatten() + } val unusedHashtags = tagsInEvent.filterNot { eventTag -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt index e790bcf0a..239c41d63 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt @@ -474,7 +474,7 @@ open class CommentPostViewModel : myMultiOrchestrator.upload( alt, contentWarningReason, - MediaCompressor.Companion.intToCompressorQuality(mediaQuality), + MediaCompressor.intToCompressorQuality(mediaQuality), server, account, context, @@ -703,5 +703,5 @@ open class CommentPostViewModel : return location!! } - override fun locationManager(): LocationState = Amethyst.Companion.instance.locationManager + override fun locationManager(): LocationState = Amethyst.instance.locationManager } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt index cbc301de9..1f8b59cff 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Emoji.kt @@ -63,7 +63,7 @@ import com.vitorpamplona.quartz.nip30CustomEmoji.pack.EmojiPackEvent import com.vitorpamplona.quartz.nip30CustomEmoji.taggedEmojis @Composable -public fun RenderEmojiPack( +fun RenderEmojiPack( baseNote: Note, actionable: Boolean, backgroundColor: MutableState, @@ -86,7 +86,7 @@ public fun RenderEmojiPack( @OptIn(ExperimentalLayoutApi::class) @Composable -public fun RenderEmojiPack( +fun RenderEmojiPack( noteEvent: EmojiPackEvent, baseNote: Note, actionable: Boolean, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt index e972fc750..949b92473 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt @@ -649,12 +649,12 @@ fun RenderPollGameResultsPreview() { Column(Modifier.padding(10.dp)) { RenderPoll( note, - false, - true, - 2, - remember { mutableStateOf(Color.Transparent) }, - mockAccountViewModel(), - EmptyNav(), + makeItShort = false, + canPreview = true, + quotesLeft = 2, + backgroundColor = remember { mutableStateOf(Color.Transparent) }, + accountViewModel = mockAccountViewModel(), + nav = EmptyNav(), ) } } @@ -758,12 +758,12 @@ fun RenderPollColorResultsPreview() { Column(Modifier.padding(10.dp)) { RenderPoll( note, - false, - true, - 2, - remember { mutableStateOf(Color.Transparent) }, - mockAccountViewModel(), - EmptyNav(), + makeItShort = false, + canPreview = true, + quotesLeft = 2, + backgroundColor = remember { mutableStateOf(Color.Transparent) }, + accountViewModel = mockAccountViewModel(), + nav = EmptyNav(), ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt index 2e178a678..a2b8773ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/PublicMessage.kt @@ -35,7 +35,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import com.vitorpamplona.amethyst.commons.model.toImmutableListOfLists import com.vitorpamplona.amethyst.model.Note -import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.RenderUserAsClickableText import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer @@ -102,7 +101,7 @@ fun DisplayUncitedUsers( nav: INav, ) { @Suppress("ProduceStateDoesNotAssignValue") - val uncitedUsers by produceState(initialValue = emptyList()) { + val uncitedUsers by produceState(initialValue = emptyList()) { val users = event.groupKeySetWithoutOwner() - event.citedUsers() if (users.isNotEmpty()) { val newUsers = accountViewModel.loadUsersSync(users.toList()) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt index 8b063890e..7c5442ff0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/TorrentComment.kt @@ -139,12 +139,12 @@ fun TorrentCommentPreview() { toPreview = { RenderTorrentComment( comment, - false, - true, - 3, - ReplyRenderType.FULL, - remember { mutableStateOf(Color.Transparent) }, - EmptyState, + makeItShort = false, + canPreview = true, + quotesLeft = 3, + unPackReply = ReplyRenderType.FULL, + backgroundColor = remember { mutableStateOf(Color.Transparent) }, + editState = EmptyState, accountViewModel = accountViewModel, nav = nav, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt index 3f5618ae1..04ae6867e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountSessionManager.kt @@ -118,7 +118,7 @@ class AccountSessionManager( } } - private suspend fun requestLoginUI() = _accountContent.update { AccountState.LoggedOff } + private fun requestLoginUI() = _accountContent.update { AccountState.LoggedOff } suspend fun loginAndStartUI( key: String, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt index 0495229ae..0b764e9e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountState.kt @@ -65,7 +65,9 @@ class CompositionObserver( private val vmStore: StoreOwnerRegistry, private val key: Any, ) : RememberObserver { - override fun onRemembered() {} + override fun onRemembered() { + // No action needed when remembered — registration happens at construction time. + } override fun onForgotten() = vmStore.composableDetached(key) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 1e0cea279..f1e4b5c51 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -357,10 +357,10 @@ class AccountViewModel( return if (isPostHidden || isDecryptedPostHidden) { // Spam + Blocked Users + Hidden Words + Sensitive Content - NoteComposeReportState(isPostHidden, false, false, isHiddenAuthor) + NoteComposeReportState(isPostHidden, isAcceptable = false, canPreview = false, isHiddenAuthor = isHiddenAuthor) } else if (isFromLoggedIn || isFromLoggedInFollow) { // No need to process if from trusted people - NoteComposeReportState(isPostHidden, true, true, isHiddenAuthor) + NoteComposeReportState(isPostHidden, isAcceptable = true, canPreview = true, isHiddenAuthor = isHiddenAuthor) } else { val newCanPreview = !note.hasAnyReports() @@ -368,7 +368,7 @@ class AccountViewModel( if (newCanPreview && newIsAcceptable) { // No need to process reports if nothing is wrong - NoteComposeReportState(isPostHidden, true, true, false) + NoteComposeReportState(isPostHidden, isAcceptable = true, canPreview = true, isHiddenAuthor = false) } else { NoteComposeReportState( isPostHidden, @@ -511,7 +511,7 @@ class AccountViewModel( }.toMutableMap() val results = - mapNotNullAsync( + mapNotNullAsync( zaps.filter { (it.request.event as? LnZapRequestEvent)?.isPrivateZap() == true }, ) { next -> val info = innerDecryptAmountMessage(next.request, next.response) @@ -1609,7 +1609,7 @@ class AccountViewModel( }.stateIn( viewModelScope, SharingStarted.WhileSubscribed(5000), - emptySet(), + emptySet(), ) val draftNoteCache = CachedDraftNotes(this) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/ChatBubbleLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/ChatBubbleLayout.kt index 072bb05cb..4fa4ac913 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/ChatBubbleLayout.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/layouts/ChatBubbleLayout.kt @@ -173,7 +173,7 @@ fun ChatBubbleLayout( private fun BubblePreview() { val bgColor = remember { - mutableStateOf(Color.Transparent) + mutableStateOf(Color.Transparent) } Column { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt index c717b982d..ac2453dec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/feed/types/RenderCreateChannelNote.kt @@ -222,8 +222,8 @@ fun RenderRelayLinePreview() { "wss://nos.lol", "http://icon.com/icon.ico", Modifier, - true, - true, + showPicture = true, + loadRobohash = true, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt index 1f7540e45..ec277266d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/datasource/FilterNip04DMs.kt @@ -35,7 +35,7 @@ fun filterNip04DMs( account: Account?, since: SincePerRelayMap?, ): List? { - if (group == null || group.isEmpty() || account == null) return null + if (group.isNullOrEmpty() || account == null) return null val userOutboxRelays = account.homeRelays.flow.value val userInboxRelays = account.dmRelays.flow.value diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt index 8b22d03ef..91addfd7a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/NewChatroomSubjectDialog.kt @@ -73,14 +73,14 @@ fun NewChatroomSubjectDialog( Surface { val groupName = remember { - mutableStateOf( + mutableStateOf( accountViewModel.account.chatroomList.rooms .get(room) ?.subject ?.value ?: "", ) } - val message = remember { mutableStateOf("") } + val message = remember { mutableStateOf("") } val scope = rememberCoroutineScope() Column( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt index aaa510974..108f67fd4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt @@ -596,7 +596,7 @@ class ChatNewMessageViewModel : toUsersTagger.run() val users = toUsersTagger.pTags?.mapTo(mutableSetOf()) { it.pubkeyHex } - if (users == null || users.isEmpty()) { + if (users.isNullOrEmpty()) { room = null updateNIP17StatusFromRoom() } else { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToPublicChat.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToPublicChat.kt index c1561c440..1163f14ad 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToPublicChat.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMessagesToPublicChat.kt @@ -29,7 +29,7 @@ import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent fun filterMessagesToPublicChat( channel: PublicChatChannel, since: SincePerRelayMap?, -): List? = +): List = channel.relays().toSet().map { RelayBasedFilter( relay = it, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt index 44bd9e3b4..006ca2832 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/datasource/subassemblies/FilterMyMessagesToLiveActivities.kt @@ -31,7 +31,7 @@ fun filterMyMessagesToLiveActivities( channel: LiveActivitiesChannel, pubKey: HexKey, since: SincePerRelayMap?, -): List? = +): List = channel.relays().toSet().map { RelayBasedFilter( relay = it, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt index 59c6800e7..310d5044a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/nip28PublicChat/metadata/ChannelMetadataViewModel.kt @@ -129,7 +129,7 @@ class ChannelMetadataViewModel : ViewModel() { val template = if (event != null) { - val hint = EventHintBundle(event, channel.relays().firstOrNull()) + val hint = EventHintBundle(event, channel.relays().firstOrNull()) ChannelMetadataEvent.build( channelName.value.text, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt index e333f7894..ad6ca0ddb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingEphemeralChatSubAssembler.kt @@ -40,7 +40,7 @@ class FollowingEphemeralChatSubAssembler( override fun updateFilter( key: ChatroomListState, since: SincePerRelayMap?, - ): List? = + ): List = listOfNotNull( filterFollowingEphemeralChats(key.account.ephemeralChatList.liveEphemeralChatList.value, since), ).flatten() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt index 8e4b0e4a8..98c66b737 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/datasource/FollowingPublicChatSubAssembler.kt @@ -40,7 +40,7 @@ class FollowingPublicChatSubAssembler( override fun updateFilter( key: ChatroomListState, since: SincePerRelayMap?, - ): List? = + ): List = listOfNotNull( filterLastMessageFollowingPublicChats(key.account.publicChatList.flowSet.value, since), filterFollowingPublicChatsCreationEvent(key.account.publicChatList.flowSet.value, since), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt index 3b669b127..ad9ad0e22 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessLobbyScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt index 1c1b7fb6d..d1a7d0e55 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chess/ChessRelaySettingsSheet.kt @@ -42,7 +42,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt index 68ad9f137..883366290 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/DiscoverLiveFeedFilter.kt @@ -117,8 +117,7 @@ open class DiscoverLiveFeedFilter( fun convertStatusToOrder(event: LiveActivitiesEvent?): Int { if (event == null) return 0 - val url = event.streaming() - if (url == null) return 0 + val url = event.streaming() ?: return 0 return when (event.status()) { StatusTag.STATUS.LIVE -> { if (OnlineChecker.isCachedAndOffline(url)) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt index 41fffe055..3c89d5e9c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip53LiveActivities/LiveActivityCard.kt @@ -238,7 +238,7 @@ fun LoadParticipants( } } - val hostsAuthor = hosts + (baseNote.author?.let { listOf(it) } ?: emptyList()) + val hostsAuthor = hosts + (baseNote.author?.let { listOf(it) } ?: emptyList()) val topFilter = accountViewModel.account.liveDiscoveryFollowLists.value diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByHashtag.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByHashtag.kt index a45973b3b..f5b4a505b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByHashtag.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/subassemblies/FilterCommunitiesByHashtag.kt @@ -34,7 +34,7 @@ fun filterCommunitiesByHashtag( hashtags: Set?, since: Long?, ): List { - if (hashtags == null || hashtags.isEmpty()) return emptyList() + if (hashtags.isNullOrEmpty()) return emptyList() val hashtags = hashtags.flatMap(::hashtagAlts).distinct().sorted() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt index f75e7d737..6fa904415 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt @@ -189,7 +189,7 @@ fun RenderContentDVMThumb( card.personalized?.let { var color = Color.DarkGray var name = "generic" - if (card.personalized == true) { + if (card.personalized) { color = MaterialTheme.colorScheme.bitcoinColor name = "Personalized" } else { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt index 14a3752a3..1297036b6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt @@ -142,7 +142,7 @@ open class NewProductViewModel : var price by mutableStateOf(TextFieldValue("")) var locationText by mutableStateOf(TextFieldValue("")) var category by mutableStateOf(TextFieldValue("")) - var condition by mutableStateOf(ConditionTag.CONDITION.USED_LIKE_NEW) + var condition by mutableStateOf(ConditionTag.CONDITION.USED_LIKE_NEW) // Invoices var canAddInvoice by mutableStateOf(false) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/subassemblies/FilterClassifiedsByHashtag.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/subassemblies/FilterClassifiedsByHashtag.kt index bc425ba1b..bf227d5e0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/subassemblies/FilterClassifiedsByHashtag.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/subassemblies/FilterClassifiedsByHashtag.kt @@ -33,7 +33,7 @@ fun filterClassifiedsByHashtag( hashtags: Set?, since: Long?, ): List? { - if (hashtags == null || hashtags.isEmpty()) return null + if (hashtags.isNullOrEmpty()) return null val hashtags = hashtags.flatMap(::hashtagAlts).distinct().sorted() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt index 53ef624e4..b00fbc9a1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/dal/GeoHashFeedFilter.kt @@ -57,7 +57,7 @@ class GeoHashFeedFilter( override fun applyFilter(newItems: Set): Set = innerApplyFilter(newItems) - private fun innerApplyFilter(collection: Collection): Set = collection.filterTo(HashSet()) { acceptableEvent(it, tag) } + private fun innerApplyFilter(collection: Collection): Set = collection.filterTo(HashSet()) { acceptableEvent(it, tag) } fun acceptableEvent( it: Note, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFeedFilterSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFeedFilterSubAssembler.kt index a6f174ab0..9d7fe94ab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFeedFilterSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/geohash/datasource/GeoHashFeedFilterSubAssembler.kt @@ -32,7 +32,7 @@ class GeoHashFeedFilterSubAssembler( override fun updateFilter( key: GeohashQueryState, since: SincePerRelayMap?, - ): List? = filterPostsByGeohash(key.geohash, key.relays, since) + ): List = filterPostsByGeohash(key.geohash, key.relays, since) /** * Only one key per hashtag. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt index fbb048075..9a95a0e46 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/hashtag/dal/HashtagFeedFilter.kt @@ -59,7 +59,7 @@ class HashtagFeedFilter( override fun applyFilter(newItems: Set): Set = innerApplyFilter(newItems) - private fun innerApplyFilter(collection: Collection): Set = collection.filterTo(HashSet()) { acceptableEvent(it, tag) } + private fun innerApplyFilter(collection: Collection): Set = collection.filterTo(HashSet()) { acceptableEvent(it, tag) } fun acceptableEvent( it: Note, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt index c45eb4b20..db41c7152 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.home import android.content.Context import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -220,7 +221,7 @@ open class ShortNotePostViewModel : var canUsePoll by mutableStateOf(false) var wantsPoll by mutableStateOf(false) var pollOptions: SnapshotStateMap = newStateMapPollOptions() - var closedAt by mutableStateOf(TimeUtils.oneDayAhead()) + var closedAt by mutableLongStateOf(TimeUtils.oneDayAhead()) // Invoices var canAddInvoice by mutableStateOf(false) @@ -554,8 +555,8 @@ open class ShortNotePostViewModel : val serverToUse = voiceSelectedServer ?: accountViewModel.account.settings.defaultFileServer uploadVoiceMessageSync( serverToUse, - { _, _ -> }, // Error handling is done by checking voiceMetadata below - ) + ) { _, _ -> } // Error handling is done by checking voiceMetadata below + // Abort if upload failed - don't post without voice data if (voiceMetadata == null) { Log.w("ShortNotePostViewModel", "Voice upload failed, aborting post") diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt index 80f623b2c..2938ad1a6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/dal/HomeLiveFilter.kt @@ -160,10 +160,8 @@ class HomeLiveFilter( val noteEvent = note.event if (noteEvent is LiveActivitiesChatMessageEvent) { - val stream = noteEvent.activityAddress() - if (stream == null) return false - val streamChannel = LocalCache.getLiveActivityChannelIfExists(stream) - if (streamChannel == null) return false + val stream = noteEvent.activityAddress() ?: return false + val streamChannel = LocalCache.getLiveActivityChannelIfExists(stream) ?: return false if (streamChannel.info?.status() != StatusTag.STATUS.LIVE) return false } @@ -194,7 +192,7 @@ class HomeLiveFilter( return collection.sortedWith( compareByDescending { followCounts[it] } - .thenByDescending { it.lastNote?.createdAt() ?: 0L } + .thenByDescending { it.lastNote?.createdAt() ?: 0L } .thenBy { it.hashCode() }, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListItem.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListItem.kt index 2ac13c5f7..369852526 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListItem.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/lists/list/PeopleListItem.kt @@ -426,7 +426,7 @@ private fun ListModifyDescriptionDialog( onDismissDialog: () -> Unit, onModifyDescription: (String) -> Unit, ) { - val updatedDescription = remember { mutableStateOf("") } + val updatedDescription = remember { mutableStateOf("") } val modifyIndicatorLabel = if (currentDescription == null) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt index eb53679fd..a0cd1da9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedContentState.kt @@ -72,7 +72,7 @@ class CardFeedContentState( val feedContent = _feedContent.asStateFlow() // Simple counter that changes when it needs to invalidate everything - private val _scrollToTop = MutableStateFlow(0) + private val _scrollToTop = MutableStateFlow(0) val scrollToTop = _scrollToTop.asStateFlow() var scrolltoTopPending = false @@ -165,13 +165,13 @@ class CardFeedContentState( val reactionsPerEvent = mutableMapOf>() notes .filter { it.event is ReactionEvent } - .forEach { + .forEach { note -> val reactedPost = - it.replyTo?.lastOrNull { + note.replyTo?.lastOrNull { it.event !is ChannelMetadataEvent && it.event !is ChannelCreateEvent } if (reactedPost != null) { - reactionsPerEvent.getOrPut(reactedPost, { mutableListOf() }).add(it) + reactionsPerEvent.getOrPut(reactedPost) { mutableListOf() }.add(note) } } @@ -192,7 +192,7 @@ class CardFeedContentState( // var newZapRequestEvent = LocalCache.checkPrivateZap(zapRequest.event as Event) // zapRequest.event = newZapRequestEvent zapsPerEvent - .getOrPut(zappedPost, { mutableListOf() }) + .getOrPut(zappedPost) { mutableListOf() } .add(CombinedZap(zapRequest, zapEvent)) } } else { @@ -215,7 +215,7 @@ class CardFeedContentState( val zapRequestNote = getNoteIfExists(zapRequest.id) if (zapRequestNote != null) { zapsPerUser - .getOrPut(author, { mutableListOf() }) + .getOrPut(author) { mutableListOf() } .add(CombinedZap(zapRequestNote, zapEvent)) } } @@ -226,13 +226,13 @@ class CardFeedContentState( val boostsPerEvent = mutableMapOf>() notes .filter { it.event is RepostEvent || it.event is GenericRepostEvent } - .forEach { + .forEach { note -> val boostedPost = - it.replyTo?.lastOrNull { + note.replyTo?.lastOrNull { it.event !is ChannelMetadataEvent && it.event !is ChannelCreateEvent } if (boostedPost != null) { - boostsPerEvent.getOrPut(boostedPost, { mutableListOf() }).add(it) + boostsPerEvent.getOrPut(boostedPost) { mutableListOf() }.add(note) } } @@ -240,42 +240,41 @@ class CardFeedContentState( val allBaseNotes = zapsPerEvent.keys + boostsPerEvent.keys + reactionsPerEvent.keys val multiCards = - allBaseNotes - .map { baseNote -> - val boostsInCard = boostsPerEvent[baseNote] ?: emptyList() - val reactionsInCard = reactionsPerEvent[baseNote] ?: emptyList() - val zapsInCard = zapsPerEvent[baseNote] ?: emptyList() + allBaseNotes.flatMap { baseNote -> + val boostsInCard = boostsPerEvent[baseNote] ?: emptyList() + val reactionsInCard = reactionsPerEvent[baseNote] ?: emptyList() + val zapsInCard = zapsPerEvent[baseNote] ?: emptyList() - val singleList = - (boostsInCard + zapsInCard.map { it.response } + reactionsInCard).groupBy { - sdf.format( - Instant - .ofEpochSecond(it.createdAt() ?: 0L) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime(), + val singleList = + (boostsInCard + zapsInCard.map { it.response } + reactionsInCard).groupBy { + sdf.format( + Instant + .ofEpochSecond(it.createdAt() ?: 0L) + .atZone(ZoneId.systemDefault()) + .toLocalDateTime(), + ) + } + + val days = singleList.keys.sortedBy { it } + + days + .mapNotNull { string -> + val sortedList = + singleList + .get(string) + ?.sortedWith(compareBy({ it.createdAt() }, { it.idHex })) + ?.reversed() + + sortedList?.chunked(30)?.map { chunk -> + MultiSetCard( + baseNote, + boostsInCard.filter { it in chunk }.toImmutableList(), + reactionsInCard.filter { it in chunk }.toImmutableList(), + zapsInCard.filter { it.response in chunk }.toImmutableList(), ) } - - val days = singleList.keys.sortedBy { it } - - days - .mapNotNull { - val sortedList = - singleList - .get(it) - ?.sortedWith(compareBy({ it.createdAt() }, { it.idHex })) - ?.reversed() - - sortedList?.chunked(30)?.map { chunk -> - MultiSetCard( - baseNote, - boostsInCard.filter { it in chunk }.toImmutableList(), - reactionsInCard.filter { it in chunk }.toImmutableList(), - zapsInCard.filter { it.response in chunk }.toImmutableList(), - ) - } - }.flatten() - }.flatten() + }.flatten() + } val userZaps = zapsPerUser @@ -290,10 +289,10 @@ class CardFeedContentState( ) } - byDay.values.map { + byDay.values.map { zaps -> ZapUserSetCard( user.key, - it + zaps .sortedWith(compareBy({ it.createdAt() }, { it.idHex() })) .reversed() .toImmutableList(), diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt index 38799f3bf..105d71a93 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/NotificationSummaryState.kt @@ -82,9 +82,9 @@ class NotificationSummaryState( Instant.ofEpochSecond(createAt).atZone(ZoneId.systemDefault()).toLocalDateTime(), ) - fun today() = sdf.format(LocalDateTime.now()) + fun today(): String = sdf.format(LocalDateTime.now()) - public suspend fun initializeSuspend() { + suspend fun initializeSuspend() { checkNotInMainThread() val currentUser = user.pubkeyHex diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt index f95b460c9..53fd1cf33 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/bookmarks/dal/UserProfileBookmarksFeedFilter.kt @@ -37,9 +37,7 @@ class UserProfileBookmarksFeedFilter( override fun feed(): List { val note = LocalCache.getOrCreateAddressableNote(BookmarkListEvent.createBookmarkAddress(user.pubkeyHex)) - val noteEvent = note.event as? BookmarkListEvent - - if (noteEvent == null) return emptyList() + val noteEvent = note.event as? BookmarkListEvent ?: return emptyList() val notes = noteEvent.publicBookmarks().mapNotNull { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/FilterUserProfilePosts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/FilterUserProfilePosts.kt index f36547074..d95d5f51b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/FilterUserProfilePosts.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/FilterUserProfilePosts.kt @@ -76,29 +76,28 @@ fun filterUserProfilePosts( user.outboxRelays()?.ifEmpty { null } ?: (user.allUsedRelays() + LocalCache.relayHints.hintsForKey(user.pubkeyHex)) - return relays - .map { relay -> - listOf( - RelayBasedFilter( - relay = relay, - filter = - Filter( - kinds = UserProfilePostKinds1, - authors = listOf(user.pubkeyHex), - limit = 500, - since = since?.get(relay)?.time, - ), - ), - RelayBasedFilter( - relay = relay, - filter = - Filter( - kinds = UserProfilePostKinds2, - authors = listOf(user.pubkeyHex), - limit = 50, - since = since?.get(relay)?.time, - ), - ), - ) - }.flatten() + return relays.flatMap { relay -> + listOf( + RelayBasedFilter( + relay = relay, + filter = + Filter( + kinds = UserProfilePostKinds1, + authors = listOf(user.pubkeyHex), + limit = 500, + since = since?.get(relay)?.time, + ), + ), + RelayBasedFilter( + relay = relay, + filter = + Filter( + kinds = UserProfilePostKinds2, + authors = listOf(user.pubkeyHex), + limit = 50, + since = since?.get(relay)?.time, + ), + ), + ) + } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileFollowersFilterSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileFollowersFilterSubAssembler.kt index 57030f718..6fe462fe8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileFollowersFilterSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileFollowersFilterSubAssembler.kt @@ -32,7 +32,7 @@ class UserProfileFollowersFilterSubAssembler( override fun updateFilter( key: UserProfileQueryState, since: SincePerRelayMap?, - ): List? = filterUserProfileFollowers(user(key), since) + ): List = filterUserProfileFollowers(user(key), since) override fun user(key: UserProfileQueryState) = key.user } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileMetadataFilterSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileMetadataFilterSubAssembler.kt index 78cde3b09..591010081 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileMetadataFilterSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/datasource/UserProfileMetadataFilterSubAssembler.kt @@ -34,7 +34,7 @@ class UserProfileMetadataFilterSubAssembler( override fun updateFilter( keys: List, since: SincePerRelayMap?, - ): List? { + ): List { val userPerRelay = mapOfSet { keys.mapTo(mutableSetOf()) { key -> key.user }.forEach { user -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportsFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportsFeedFilter.kt index 0d6f9d4fa..2027b5106 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportsFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/reports/dal/UserProfileReportsFeedFilter.kt @@ -38,7 +38,7 @@ class UserProfileReportsFeedFilter( private fun innerApplyFilter(collection: Collection): Set = collection - .filterTo(mutableSetOf()) { + .filterTo(mutableSetOf()) { it.event is ReportEvent && it.event?.isTaggedUser(user.pubkeyHex) == true } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListViewModel.kt index 25081c10b..abaf3faab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/blocked/BlockedRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class BlockedRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.blockedRelayList.flow.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListViewModel.kt index 608eb9405..1c94de0f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/broadcast/BroadcastRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class BroadcastRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.broadcastRelayList.flow.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelaySuggestionState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelaySuggestionState.kt index cd772c2f9..538df3e00 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelaySuggestionState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/common/RelaySuggestionState.kt @@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common import androidx.compose.runtime.Stable import com.vitorpamplona.amethyst.model.LocalCache -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.MutableStateFlow @@ -48,7 +47,7 @@ class RelaySuggestionState { .sortedBy { it.url } .take(20) } else { - emptyList() + emptyList() } }.flowOn(Dispatchers.IO) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/favorites/FavoriteRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/favorites/FavoriteRelayListViewModel.kt index a0d3ff0a6..45a95c11b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/favorites/FavoriteRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/favorites/FavoriteRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class FavoriteRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.favoriteRelayList.flow.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListViewModel.kt index b4af90aeb..837966624 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/indexer/IndexerRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class IndexerRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.indexerRelayList.flowNoDefaults.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListViewModel.kt index 628864a70..a3e5f9f41 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip37/PrivateOutboxRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class PrivateOutboxRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.privateStorageRelayList.flow.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListViewModel.kt index 0d32e58c4..e2a0f1359 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/proxy/ProxyRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class ProxyRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.proxyRelayList.flow.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListViewModel.kt index bbbbfc148..e2e3ba0aa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/search/SearchRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class SearchRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.searchRelayList.flowNoDefaults.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListViewModel.kt index 057c71098..c6b46496e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/trusted/TrustedRelayListViewModel.kt @@ -26,7 +26,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @Stable class TrustedRelayListViewModel : BasicRelaySetupInfoModel() { - override fun getRelayList(): List? = + override fun getRelayList(): List = account.trustedRelayList.flow.value .toList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt index 8855dd149..9947d9cda 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/search/SearchBarViewModel.kt @@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.relayClient.searchCommand.SearchQueryState import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder +import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinLookupException import com.vitorpamplona.quartz.nip05DnsIdentifiers.namecoin.NamecoinNameResolver import com.vitorpamplona.quartz.nip10Notes.content.findHashtags import kotlinx.coroutines.Dispatchers @@ -43,12 +44,13 @@ import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update @@ -62,8 +64,8 @@ class SearchBarViewModel( val focusRequester = FocusRequester() var searchValue by mutableStateOf("") - val invalidations = MutableStateFlow(0) - val searchValueFlow = MutableStateFlow("") + val invalidations = MutableStateFlow(0) + val searchValueFlow = MutableStateFlow("") val searchTerm = searchValueFlow @@ -75,27 +77,73 @@ class SearchBarViewModel( val searchDataSourceState = SearchQueryState(MutableStateFlow(searchValue), account) /** - * Resolves Namecoin identifiers (.bit / d/ / id/) via ElectrumX and - * returns the matching [User] from LocalCache, or null. + * Observable state for Namecoin resolution in the search bar. + * Allows the UI to show loading spinners, resolved profiles, and + * specific error messages ("name not found" vs "servers unreachable"). */ - private val namecoinResolvedUser = + sealed class NamecoinSearchState { + data object Idle : NamecoinSearchState() + + data object Loading : NamecoinSearchState() + + data class Resolved( + val user: User, + ) : NamecoinSearchState() + + data class NotFound( + val name: String, + ) : NamecoinSearchState() + + data class Expired( + val name: String, + ) : NamecoinSearchState() + + data object ServersUnreachable : NamecoinSearchState() + } + + /** + * Resolves Namecoin identifiers (.bit / d/ / id/) via ElectrumX. + * Emits typed state so the UI can show loading, resolved profile, or + * specific error messages. + */ + val namecoinSearchState: StateFlow = searchValueFlow .debounce(400) .distinctUntilChanged() - .filter { NamecoinNameResolver.isNamecoinIdentifier(it) } - .map { term -> + .mapLatest { term -> + if (!NamecoinNameResolver.isNamecoinIdentifier(term)) { + return@mapLatest NamecoinSearchState.Idle + } try { val result = Amethyst.instance.namecoinResolver.resolve(term) if (result != null) { - LocalCache.getOrCreateUser(result.pubkey) + NamecoinSearchState.Resolved(LocalCache.getOrCreateUser(result.pubkey)) } else { - null + NamecoinSearchState.NotFound(term) } + } catch (e: kotlinx.coroutines.CancellationException) { + throw e + } catch (e: NamecoinLookupException.NameNotFound) { + NamecoinSearchState.NotFound(e.name) + } catch (e: NamecoinLookupException.NameExpired) { + NamecoinSearchState.Expired(e.name) + } catch (e: NamecoinLookupException.ServersUnreachable) { + NamecoinSearchState.ServersUnreachable } catch (_: Exception) { - null + NamecoinSearchState.ServersUnreachable } }.flowOn(Dispatchers.IO) - .stateIn(viewModelScope, WhileSubscribed(5000), null) + .stateIn(viewModelScope, WhileSubscribed(5000), NamecoinSearchState.Idle) + + /** Convenience: the resolved user (or null) for combining with local search results. */ + private val namecoinResolvedUser = + namecoinSearchState + .map { state -> + when (state) { + is NamecoinSearchState.Resolved -> state.user + else -> null + } + }.stateIn(viewModelScope, WhileSubscribed(5000), null) val searchResultsUsers = combine( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt index 7d2bcf860..ebb8058e8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/AllSettingsScreen.kt @@ -41,8 +41,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt index 0471f74db..e995b1377 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ReactionsSettingsScreen.kt @@ -103,7 +103,7 @@ fun ReactionsSettingsScreen( @Composable fun ReactionsSettingsContent(accountViewModel: AccountViewModel) { val reactionRowItems by accountViewModel.reactionRowItemsFlow().collectAsStateWithLifecycle() - var items by remember(reactionRowItems) { mutableStateOf(reactionRowItems.toMutableList()) } + var items by remember(reactionRowItems) { mutableStateOf(reactionRowItems.toList()) } fun save(newItems: List) { items = newItems.toMutableList() diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt index 5b6f0cdbb..21760c45e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/SecurityFiltersScreen.kt @@ -376,7 +376,7 @@ fun MutedWordActionOptions( ) { val isMutedWord by observeAccountIsHiddenWord(accountViewModel.account, word) - if (isMutedWord == true) { + if (isMutedWord) { ShowWordButton { if (!accountViewModel.isWriteable()) { accountViewModel.toastManager.toast( diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt index fac25dca4..583349d0d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/threadview/ThreadFeedView.kt @@ -635,12 +635,12 @@ private fun FullBleedNoteCompose( } else if (noteEvent is InteractiveStoryBaseEvent) { RenderInteractiveStory( baseNote, - false, - true, - 3, - backgroundColor, - accountViewModel, - nav, + makeItShort = false, + canPreview = true, + quotesLeft = 3, + backgroundColor = backgroundColor, + accountViewModel = accountViewModel, + nav = nav, ) } else if (noteEvent is GitPatchEvent) { RenderGitPatchEvent(baseNote, makeItShort = false, canPreview = true, quotesLeft = 3, backgroundColor = backgroundColor, accountViewModel = accountViewModel, nav = nav) @@ -842,7 +842,7 @@ private fun RenderClassifiedsReaderForThread( Row(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp)) { Column { - if (imageSet != null && imageSet.isNotEmpty()) { + if (!imageSet.isNullOrEmpty()) { AutoNonlazyGrid(imageSet.size) { ZoomableContentView( content = imageSet[it], diff --git a/amethyst/src/main/res/values-cs-rCZ/strings.xml b/amethyst/src/main/res/values-cs-rCZ/strings.xml index 4850ce01d..1383d913e 100644 --- a/amethyst/src/main/res/values-cs-rCZ/strings.xml +++ b/amethyst/src/main/res/values-cs-rCZ/strings.xml @@ -1042,6 +1042,21 @@ Olajkovat Zap Změnit rychlé reakce + Nastavení reakcí + Nastavte, která tlačítka reakcí se zobrazují, jejich pořadí a zda se mají zobrazovat počty. + Povoleno + Zobrazit počet + Změnit pořadí + Odpovědět + Odpovědět na tuto poznámku + Boost + Repostovat nebo citovat tuto poznámku + To se mi líbí + Reagovat na tuto poznámku pomocí emoji + Zap + Poslat lightning platbu autorovi + Sdílet + Sdílet tuto poznámku externě Obrázek profilu %1$s Relé %1$s Rozbalit seznam relací diff --git a/amethyst/src/main/res/values-de-rDE/strings.xml b/amethyst/src/main/res/values-de-rDE/strings.xml index d1fa799fd..c5cadc07b 100644 --- a/amethyst/src/main/res/values-de-rDE/strings.xml +++ b/amethyst/src/main/res/values-de-rDE/strings.xml @@ -1047,6 +1047,21 @@ anz der Bedingungen ist erforderlich Gefällt mir Zap Schnelle Reaktionen ändern + Reaktions-Einstellungen + Konfigurieren Sie, welche Reaktionsschaltflächen angezeigt werden, ihre Reihenfolge und ob Zähler angezeigt werden sollen. + Aktiviert + Anzahl anzeigen + Neu anordnen + Antworten + Auf diese Notiz antworten + Boost + Diese Notiz reposten oder zitieren + Gefällt mir + Mit einem Emoji auf diese Notiz reagieren + Zap + Eine Lightning-Zahlung an den Autor senden + Teilen + Diese Notiz extern teilen Profilbild von %1$s %1$s weiterleiten Rela-Liste erweitern diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml index 7f4b32eb1..f57c2bdb3 100644 --- a/amethyst/src/main/res/values-pl-rPL/strings.xml +++ b/amethyst/src/main/res/values-pl-rPL/strings.xml @@ -688,6 +688,7 @@ Zasady i warunki użytkowania Nie dotyczy Błędy i powiadomienia z tego transmitera + Aktywne subskrypcje Brak aktywnych subskrypcji dla tego transmitera od %1$s do %1$s @@ -1037,6 +1038,20 @@ Lubię Zap Zmień odzew + Ustawienia reakcji + Skonfiguruj które przyciski reakcji będą wyświetlane, ich kolejność i czy wyświetlić liczniki. + Włączone + Pokaż licznik + Odpowiedz + Odpowiedz na ten wpis + Udostępnij + Udostępnij lub zacytuj ten wpis + Lubię + Zareaguj na ten wpis, używając emoji + Zap + Wyślij płatność Lightning do autora + Prześlij dalej + Prześlij ten wpis na zewnątrz Zdjęcie profilowe %1$s Transmiter %1$s Rozwiń listę transmiterów @@ -1110,6 +1125,7 @@ Transmitery, którym ufasz, nie potrzebujesz połączenia Tor Ulubione kanały transmitera Ulubione kanały transmitera + Transmitery, które często przeglądasz Transmitery Proxy Transmitery Proxy Transmitery agregatora, z których aplikacja musi pobierać kanały, takie jak filter.nostr.wine. To zastępuje model skrzynki nadawczej i sprawia, że aplikacja łączy się tylko z transmiterami z Twojej listy. @@ -1301,7 +1317,11 @@ Akceptuj Odrzuć Nowa gra + Nowa gra w Szachy + Ładowanie gry\u2026 Gra nie znaleziona + Ta gra mogła się skończyć lub czeka na przeciwnika. + ID gry: %1$s\u2026 i %1$d innych Usuń %1$s @@ -1313,6 +1333,7 @@ Odznaki profilowe Zablokowane Transmitery Serwery Blossom + Autentykacja Blossom Transmitery Nadawcze Lista zakładek Kalendarz @@ -1323,22 +1344,32 @@ Transmitery DM Ogłoszenia Komentarze + Lista społeczności + Usunięcia Wersje robocze Pakiety emoji Lista Pakietów Emoji Serwery Plików + Dane medyczne + Indeks listy transmiterów Zapy + Zapytanie NWC + Odpowiedź NWC Prywatne Zapy Blogi Pokój spotkań Strefa spotkań Profil Lista zablokowanych + NIP + Nostr Connect + OTS Listy osób Zdjęcia Pineski Sondaż Odpowiedź w sondażu + Wiadomości NIP-04 Transmitery Prywatne Transmitery Proxy Wiadomość publiczna @@ -1358,6 +1389,7 @@ Komentarze torrentów Zaufane Transmitery Zaufani dostawcy + Wideo Filmiki Odpowiedź głosowa Wiki diff --git a/amethyst/src/main/res/values-pt-rBR/strings.xml b/amethyst/src/main/res/values-pt-rBR/strings.xml index f58008471..cb196c727 100644 --- a/amethyst/src/main/res/values-pt-rBR/strings.xml +++ b/amethyst/src/main/res/values-pt-rBR/strings.xml @@ -1042,6 +1042,21 @@ Gostar Zap Mudar reações rápidas + Configurações de Reações + Configure quais botões de reação são exibidos, sua ordem e se os contadores devem ser mostrados. + Ativado + Mostrar contagem + Reordenar + Responder + Responder a esta nota + Boost + Repostar ou citar esta nota + Curtir + Reagir a esta nota com um emoji + Zap + Enviar um pagamento lightning ao autor + Compartilhar + Compartilhar esta nota externamente Foto de perfil de %1$s Repassar %1$s Expandir lista de repasse diff --git a/amethyst/src/main/res/values-sv-rSE/strings.xml b/amethyst/src/main/res/values-sv-rSE/strings.xml index ec57be293..efe822766 100644 --- a/amethyst/src/main/res/values-sv-rSE/strings.xml +++ b/amethyst/src/main/res/values-sv-rSE/strings.xml @@ -1041,6 +1041,21 @@ Gilla Zap Ändra Snabba Reaktioner + Reaktionsinställningar + Konfigurera vilka reaktionsknappar som visas, deras ordning och om räknare ska visas. + Aktiverad + Visa antal + Ändra ordning + Svara + Svara på denna notis + Boosta + Reposta eller citera denna notis + Gilla + Reagera på denna notis med en emoji + Zap + Skicka en lightning-betalning till författaren + Dela + Dela denna notis externt %1$s Profilbild Relä %1$s Expandera relälistan diff --git a/amethyst/src/main/res/values-zh-rCN/strings.xml b/amethyst/src/main/res/values-zh-rCN/strings.xml index d90248bd8..f8b49b8c8 100644 --- a/amethyst/src/main/res/values-zh-rCN/strings.xml +++ b/amethyst/src/main/res/values-zh-rCN/strings.xml @@ -42,12 +42,12 @@ 举报明确内容 举报非法行为 举报恶意软件 - ???Report Mod??? + 举报 Mod 恶意软件 - ???Mod??? + Mod 你正在使用公钥,公钥是只读的。使用私钥登录以便回复 你正在使用公钥,公钥是只读的。使用私钥登录以便提升帖子 - 使用私钥登录以便点赞帖子 + 你正在使用公钥,公钥是只读的。使用私钥登录以点赞帖子 没有设置打闪金额。长按以更改 你正在使用公钥,公钥是只读的。使用私钥登录以便发送打闪 你正在使用公钥,公钥是只读的。使用私钥登录以便能够关注 @@ -89,7 +89,7 @@ 显示更多 闪电发票 付款 - 闪电小费 + Lightning 小费 给收款方的留言 非常感谢! 聪金额 @@ -191,7 +191,7 @@ 会话 Mod 队列 - 动态 + 笔记 回复 你的 相册 @@ -322,7 +322,7 @@ 徽章奖励授予 文本已复制到剪贴板 复制作者的 @npub 到剪贴板 - 复制文章ID (@note1) 到剪贴板 + 已复制笔记ID (@note1) 到剪贴板 选择文本 "<无法解密私密消息>\n\n;你被 %1$s 和 %2$s 之间的私人/加密会话引用。" 添加新账户 @@ -337,7 +337,7 @@ 分享浏览网址 分享 \@提及 - 引用 + 笔记ID 复制 删除 取关 @@ -443,6 +443,7 @@ 打闪金额 这种投票只允许每个用户一票 "正在查找事件 %1$s" + 发送打闪 添加公开消息 添加私信 添加发票消息 @@ -524,7 +525,7 @@ \n轻按下方刷新,或者轻按“+”按钮新建一个。 新建 - 添加作者到关注集 + 添加作者到关注列表 从列表中添加或删除用户,或用此用户创建一个新列表。 关注集的图标 %1$s 是公开成员 @@ -690,6 +691,17 @@ 使用条款 N/A 该中继的错误和通知 + 活跃订阅 + 待处理发件箱事件 + 请求订阅(%1$d) + 计算订数 (%1$d) + 发件箱事件(%1$d) + 此中继没有活动订阅 + %1$d 位作者 + %1$d 个 id + 自 %1$s + 直到 %1$s + 限制 %1$d 消息长度 订阅 筛选器 @@ -749,9 +761,14 @@ 此社区没有描述或规则。联系群主来添加 敏感内容 在显示此内容之前添加敏感内容警告 + 用户界面首选项 偏好设置 用户首选项 + 翻译 + 反应 设置 + 账户设置 + 应用程序设置 始终 仅限 WiFi 未计量的 WiFi @@ -781,6 +798,9 @@ 垃圾邮件 静音。点击取消静音 声音开启。点击静音 + 后退 %d 秒 + 前进 %d 秒 + 画中画 搜索本地和远程记录 Nostr 地址已验证 Nostr 地址验证失败 @@ -1027,6 +1047,21 @@ 点赞 打闪 修改快速回应 + 反应设置 + 配置显示的反应按钮、它们的顺序以及是否显示计数器。 + 已启用 + 显示计数 + 调整顺序 + 回复 + 回复此笔记 + Boost + 转发或引用此笔记 + 点赞 + 用表情符号对此笔记进行反应 + 打闪 + 给作者发送 Lightning 网络付款 + 分享 + 对外分享此笔记 %1$s 的个人头像 中继器 %1$s 展开中继列表 @@ -1037,7 +1072,7 @@ 比特币发票 取消比特币发票 取消出售物品 - Zapraiser + 打闪筹款方 取消 Zapraiser 地点 移除地点 @@ -1098,6 +1133,9 @@ 可信中继 可信中继 无需使用 Tor 进行连接的可信中继 + 喜爱的中继源 + 喜爱的中继源 + 经常前去查看全局源的中继 代理中继 代理中继 聚合器中继是应用获取资讯源时使用的中继(例如:filter.nostr.wine),设置这个列表将覆盖信箱模型的行为,使得应用只会连接到这个列表中的中继以获取内容。 @@ -1143,6 +1181,7 @@ 图钉 扫描二维码 导航到第三方钱包提供商 Alby + 选择日期 无法回复笔记草稿 无法引用笔记草稿 无法回应笔记草稿 @@ -1279,5 +1318,149 @@ 确认 下一个 添加投票选项按钮 + 返回 + 批准 + 已连接 + 社交证明 + 提交 + 重启 + 接受 + 拒绝 + 新游戏 + 新的国际象棋游戏 + 正在加载游戏\u2026 + 未找到游戏 + 这个游戏可能已经结束或正在等待对手。 + 游戏ID: %1$s\u2026 + 和另外 %1$d + 移除 %1$s + 发件箱中继 + 应用程序 + 应用推荐 + 用户设置 + 音频标题 + 音轨 + 徽章奖励 + 徽章定义 + 个人资料徽章 + 中继黑名单 + Blossom 服务器 + Blossom 认证 + 广播中继 + 书签列表 + 日预约 + 日历 + 预约 + 预约确认请求 + 国际象棋游戏 + Chess 网站认证 + 喜爱的中继 + 国际象棋挑战 + 接受国际象棋游戏挑战 + 棋子移动 + 国际象棋游戏结束 + 和棋请求 + 频道定义 + 频道隐藏消息 + 频道列表 + 频道消息 + 频道元数据 + 频道静音用户 + 私信文件 + 私信消息 + 私信中继 + 分类广告 + 评论 + 社区定义 + 社区列表 + 社区帖子 + 关注列表 + 删除 + 草稿 + 表情包 + 表情包列表 + 临时聊天 + 临时聊天室 + 文件标题 + 资料页图库 + 文件服务器 + Blob 数据 + Blob 头部 + 医疗数据 + 关注包 + 转发(16) + Geohash 关注 + 包装礼物 + Git 问题 + Git 补丁 + Git 仓库 + Git 回复 + 打闪目标 + 话题关注 + 精彩场面 + Http 认证 + 索引中继列表 + 探险前言 + 探险场景 + 探险阅读 + 已命名书签 + 实时聊天 + 直播 + 打闪 + NWC 请求 + NWC 响应 + 私下打闪 + 打闪请求 + 博客 + 会议室 + 房间状态 + 会议空间 + 个人资料 + 静音列表 + NNS + NIP + Nostr 连接 + DVM 状态 + DVM 内容请求 + DVM 内容响应 + DVM 用户请求 + DVM 用户响应 + OTS + PayTo + 人员列表 + 图片 + 置顶 + 打闪投票 + 投票 + 投票响应 + NIP-04 私信 + 私密中继 + 代理中继 + 公开消息 + 反应 + 名片 + 中继认证 + 中继发现 + 中继监视器公告 + 中继集合 + 举报 + 转发 + 用户删除 + 密封信息 + 搜索中继 + 用户状态 + 笔记 + 编辑 + 种子 + 种子注释 + 可信中继 + 可信的提供商 + 视频 (回复) + 短篇 (回复) + 视频 + 短篇 + 语音消息 + 语音回复 + 维基 diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt index 124614ecb..ccf648e46 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/lang/LanguageTranslatorService.kt @@ -33,6 +33,7 @@ import com.google.mlkit.nl.translate.TranslatorOptions import com.vitorpamplona.amethyst.service.checkNotInMainThread import com.vitorpamplona.quartz.utils.urldetector.detection.UrlDetector import kotlinx.coroutines.CancellationException +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.regex.Pattern @@ -44,7 +45,7 @@ data class ResultOrError( ) object LanguageTranslatorService { - var executorService = Executors.newCachedThreadPool() + var executorService: ExecutorService = Executors.newCachedThreadPool() private val options = LanguageIdentificationOptions @@ -53,8 +54,8 @@ object LanguageTranslatorService { .setConfidenceThreshold(0.6f) .build() private val languageIdentification = LanguageIdentification.getClient(options) - val lnRegex = Pattern.compile("\\blnbc[a-z0-9]+\\b", Pattern.CASE_INSENSITIVE) - val tagRegex = + val lnRegex: Pattern = Pattern.compile("\\blnbc[a-z0-9]+\\b", Pattern.CASE_INSENSITIVE) + val tagRegex: Pattern = Pattern.compile( "(nostr:)?@?(nsec1|npub1|nevent1|naddr1|note1|nprofile1|nrelay1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)", Pattern.CASE_INSENSITIVE, diff --git a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt index b80c289f5..7ba915c3e 100644 --- a/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt +++ b/amethyst/src/play/java/com/vitorpamplona/amethyst/service/notifications/PushNotificationReceiverService.kt @@ -55,7 +55,7 @@ class PushNotificationReceiverService : FirebaseMessagingService() { } } - private suspend fun parseMessage(params: Map): GiftWrapEvent? { + private fun parseMessage(params: Map): GiftWrapEvent? { params["encryptedEvent"]?.let { eventStr -> (Event.fromJson(eventStr) as? GiftWrapEvent)?.let { return it diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXServer.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXServer.kt index 67e093e07..f31edfe7d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXServer.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXServer.kt @@ -48,6 +48,30 @@ data class ElectrumxServer( val trustAllCerts: Boolean = false, ) +/** + * Specific exception types for Namecoin resolution failures. + * Allows callers to distinguish "name doesn't exist" from "servers unreachable". + */ +sealed class NamecoinLookupException( + message: String, + cause: Throwable? = null, +) : Exception(message, cause) { + /** The name was queried successfully but does not exist on the blockchain. */ + class NameNotFound( + val name: String, + ) : NamecoinLookupException("Name not found: $name") + + /** The name has expired (>36000 blocks since last update). */ + class NameExpired( + val name: String, + ) : NamecoinLookupException("Name expired: $name") + + /** All ElectrumX servers were unreachable or returned errors. */ + class ServersUnreachable( + val lastError: Throwable? = null, + ) : NamecoinLookupException("All ElectrumX servers unreachable", lastError) +} + /** Well-known public Namecoin ElectrumX servers (clearnet). */ val DEFAULT_ELECTRUMX_SERVERS = listOf( diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/NamecoinNameResolver.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/NamecoinNameResolver.kt index b63735330..e9f4e07d0 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/NamecoinNameResolver.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/NamecoinNameResolver.kt @@ -206,16 +206,43 @@ class NamecoinNameResolver( // Extended form: "nostr": { "names": {...}, "relays": {...} } if (nostrField is JsonObject) { val names = nostrField["names"]?.jsonObject ?: return null - val pubkeyElem = names[parsed.localPart] ?: names["_"] // fall back to root - val pubkey = (pubkeyElem as? JsonPrimitive)?.content ?: return null - if (!isValidPubkey(pubkey)) return null + + // Resolve: exact match → "_" root → first entry (root lookups only) + val resolvedLocalPart: String + val pubkey: String + + val exactMatch = names[parsed.localPart] + val rootMatch = names["_"] + val firstEntry = if (parsed.localPart == "_") names.entries.firstOrNull() else null + + when { + exactMatch is JsonPrimitive && isValidPubkey(exactMatch.content) -> { + resolvedLocalPart = parsed.localPart + pubkey = exactMatch.content + } + + rootMatch is JsonPrimitive && isValidPubkey(rootMatch.content) -> { + resolvedLocalPart = "_" + pubkey = rootMatch.content + } + + firstEntry != null && firstEntry.value is JsonPrimitive && + isValidPubkey((firstEntry.value as JsonPrimitive).content) -> { + resolvedLocalPart = firstEntry.key + pubkey = (firstEntry.value as JsonPrimitive).content + } + + else -> { + return null + } + } val relays = extractRelays(nostrField, pubkey) return NamecoinNostrResult( pubkey = pubkey.lowercase(), relays = relays, namecoinName = parsed.namecoinName, - localPart = parsed.localPart, + localPart = resolvedLocalPart, ) } diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXClient.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXClient.kt index 9043a1d8f..c56dd72b1 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXClient.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip05DnsIdentifiers/namecoin/ElectrumXClient.kt @@ -44,6 +44,7 @@ import java.net.Socket import java.security.MessageDigest import java.security.SecureRandom import java.security.cert.X509Certificate +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicInteger import javax.net.SocketFactory import javax.net.ssl.SSLContext @@ -83,7 +84,7 @@ class ElectrumXClient( isLenient = true } private val requestId = AtomicInteger(0) - private val mutex = Mutex() + private val serverMutexes = ConcurrentHashMap() companion object { private const val PROTOCOL_VERSION = "1.4" @@ -121,9 +122,13 @@ class ElectrumXClient( server: ElectrumxServer = DEFAULT_ELECTRUMX_SERVERS.first(), ): NameShowResult? = withContext(Dispatchers.IO) { + val mutex = serverMutexes.getOrPut("${server.host}:${server.port}") { Mutex() } mutex.withLock { try { connectAndQuery(identifier, server) + } catch (e: NamecoinLookupException) { + // Propagate name-not-found and expired — these are definitive answers. + throw e } catch (e: Exception) { // Log but don't crash — callers handle null gracefully. e.printStackTrace() @@ -137,16 +142,28 @@ class ElectrumXClient( * * @param identifier Full Namecoin name, e.g. "d/example" * @param servers Ordered server list to try; defaults to [DEFAULT_ELECTRUMX_SERVERS] + * @throws NamecoinLookupException.NameNotFound if the name definitively doesn't exist + * @throws NamecoinLookupException.NameExpired if the name has expired + * @throws NamecoinLookupException.ServersUnreachable if all servers failed with connection errors */ override suspend fun nameShowWithFallback( identifier: String, servers: List, ): NameShowResult? { + var lastError: Exception? = null for (server in servers) { - val result = nameShow(identifier, server) - if (result != null) return result + try { + val result = nameShow(identifier, server) + if (result != null) return result + } catch (e: NamecoinLookupException.NameNotFound) { + throw e // Definitive answer from blockchain — no point trying other servers + } catch (e: NamecoinLookupException.NameExpired) { + throw e // Definitive answer + } catch (e: Exception) { + lastError = e // Server error — try next server + } } - return null + throw NamecoinLookupException.ServersUnreachable(lastError) } // ── internals ────────────────────────────────────────────────────── @@ -175,7 +192,7 @@ class ElectrumXClient( writer.println(historyReq) val historyResponse = reader.readLine() ?: return null val historyEntries = parseHistoryResponse(historyResponse) ?: return null - if (historyEntries.isEmpty()) return null + if (historyEntries.isEmpty()) throw NamecoinLookupException.NameNotFound(identifier) // 4. Get the latest transaction (last entry = most recent update) val latestEntry = historyEntries.last() @@ -196,7 +213,7 @@ class ElectrumXClient( if (currentHeight != null && height > 0) { val blocksSinceUpdate = currentHeight - height if (blocksSinceUpdate >= NAME_EXPIRE_DEPTH) { - return null // Name has expired + throw NamecoinLookupException.NameExpired(identifier) } } diff --git a/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip05/namecoin/NamecoinNameResolverTest.kt b/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip05/namecoin/NamecoinNameResolverTest.kt index 42488cbcb..52822c49c 100644 --- a/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip05/namecoin/NamecoinNameResolverTest.kt +++ b/quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip05/namecoin/NamecoinNameResolverTest.kt @@ -115,6 +115,36 @@ class NamecoinNameResolverTest { assertEquals("aaaa000000000000000000000000000000000000000000000000000000000001", result!!.pubkey) } + @Test + fun `root lookup falls back to first entry when no underscore key`() { + val value = """{ + "nostr": { + "names": { + "m": "6cdebccabda1dfa058ab85352a79509b592b2bdfa0370325e28ec1cb4f18667d" + } + } + }""" + + val result = extractNostrFromValue(value, "d/testls", "_") + assertNotNull(result) + assertEquals("6cdebccabda1dfa058ab85352a79509b592b2bdfa0370325e28ec1cb4f18667d", result!!.pubkey) + assertEquals("m", result.localPart) + } + + @Test + fun `non-root lookup does NOT fall back to first entry`() { + val value = """{ + "nostr": { + "names": { + "m": "6cdebccabda1dfa058ab85352a79509b592b2bdfa0370325e28ec1cb4f18667d" + } + } + }""" + + val result = extractNostrFromValue(value, "d/testls", "alice") + assertNull(result) + } + // ── Value format: id/ namespace ──────────────────────────────────── @Test @@ -209,9 +239,40 @@ class NamecoinNameResolverTest { // Extended form if (nostrField is kotlinx.serialization.json.JsonObject) { val names = nostrField["names"]?.jsonObject ?: return null - val pubkeyElem = names[localPart] ?: names["_"] ?: return null - val pubkey = (pubkeyElem as? kotlinx.serialization.json.JsonPrimitive)?.content ?: return null - if (!pubkey.matches(Regex("^[0-9a-fA-F]{64}$"))) return null + + // Resolve: exact match → "_" root → first entry (root lookups only) + val resolvedLocalPart: String + val pubkey: String + + val exactMatch = names[localPart] + val rootMatch = names["_"] + val firstEntry = if (localPart == "_") names.entries.firstOrNull() else null + + when { + exactMatch is kotlinx.serialization.json.JsonPrimitive && + exactMatch.content.matches(Regex("^[0-9a-fA-F]{64}$")) -> { + resolvedLocalPart = localPart + pubkey = exactMatch.content + } + + rootMatch is kotlinx.serialization.json.JsonPrimitive && + rootMatch.content.matches(Regex("^[0-9a-fA-F]{64}$")) -> { + resolvedLocalPart = "_" + pubkey = rootMatch.content + } + + firstEntry != null && firstEntry.value is kotlinx.serialization.json.JsonPrimitive && + (firstEntry.value as kotlinx.serialization.json.JsonPrimitive) + .content + .matches(Regex("^[0-9a-fA-F]{64}$")) -> { + resolvedLocalPart = firstEntry.key + pubkey = (firstEntry.value as kotlinx.serialization.json.JsonPrimitive).content + } + + else -> { + return null + } + } val relays = try { @@ -227,7 +288,7 @@ class NamecoinNameResolverTest { pubkey = pubkey.lowercase(), relays = relays, namecoinName = namecoinName, - localPart = localPart, + localPart = resolvedLocalPart, ) } return null