From 2d830b778ffb0a1319bc9aa9b575575be37d9bf4 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Wed, 15 Jul 2026 17:57:55 +0700 Subject: [PATCH] clean up --- .../kotlin/su/reya/coop/screens/HomeScreen.kt | 8 +++--- .../su/reya/coop/screens/NewChatScreen.kt | 2 +- .../commonMain/kotlin/su/reya/coop/Room.kt | 9 ++----- .../kotlin/su/reya/coop/nostr/Messaging.kt | 8 ++++++ .../kotlin/su/reya/coop/nostr/Nostr.kt | 10 +------ .../su/reya/coop/nostr/ProfileManager.kt | 27 +++++++++++++++++++ .../su/reya/coop/repository/ChatRepository.kt | 9 ++++--- .../su/reya/coop/viewmodel/ProfileCache.kt | 2 +- 8 files changed, 50 insertions(+), 25 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt index 1a337d1..4220715 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/HomeScreen.kt @@ -98,9 +98,9 @@ import su.reya.coop.RoomKind import su.reya.coop.RoomUiState import su.reya.coop.Screen import su.reya.coop.ago -import su.reya.coop.flow import su.reya.coop.shared.Avatar import su.reya.coop.shared.getExpressiveFontFamily +import su.reya.coop.uiStateFlow import su.reya.coop.viewmodel.AccountViewModel import su.reya.coop.viewmodel.ChatViewModel @@ -620,9 +620,9 @@ fun NewRequests(requests: List) { val firstRoom = requests.getOrNull(0) val secondRoom = requests.getOrNull(1) - val firstRoomState by (firstRoom as Room).flow(profileCache) + val firstRoomState by (firstRoom as Room).uiStateFlow(profileCache) .collectAsStateWithLifecycle(RoomUiState()) - val secondRoomState by (secondRoom ?: firstRoom).flow(profileCache) + val secondRoomState by (secondRoom ?: firstRoom).uiStateFlow(profileCache) .collectAsStateWithLifecycle(RoomUiState()) val supportingText = when { @@ -695,7 +695,7 @@ fun NewRequests(requests: List) { @Composable fun ChatRoom(room: Room, onClick: () -> Unit) { val profileCache = LocalProfileCache.current - val roomState by room.flow(profileCache).collectAsStateWithLifecycle(RoomUiState()) + val roomState by room.uiStateFlow(profileCache).collectAsStateWithLifecycle(RoomUiState()) ListItem( modifier = Modifier.clickable(onClick = onClick), diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/NewChatScreen.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/NewChatScreen.kt index a8d1076..c28de53 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/screens/NewChatScreen.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/screens/NewChatScreen.kt @@ -397,7 +397,7 @@ fun ContactListItem( supportingContent = { Text(text = pubkey.short()) }, content = { Text( - text = profile?.name ?: "", + text = profile?.name ?: "Unknown", style = MaterialTheme.typography.titleMediumEmphasized, ) } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/Room.kt b/shared/src/commonMain/kotlin/su/reya/coop/Room.kt index 2a01f29..d761aad 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/Room.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/Room.kt @@ -112,13 +112,8 @@ fun UnsignedEvent.roomId(): Long { val pubkeys: MutableList = mutableListOf() pubkeys.add(this.author()) pubkeys.addAll(this.tags().publicKeys()) - - // Sort and hash the list of public keys - val sortedUniqueKeys = pubkeys - .distinctBy { it.toBech32() } - .sortedBy { it.toBech32() } - - return sortedUniqueKeys.hashCode().toLong() + + return pubkeys.map { it.toBech32() }.distinct().sorted().hashCode().toLong() } fun Timestamp.formatAsTime(): String { diff --git a/shared/src/commonMain/kotlin/su/reya/coop/nostr/Messaging.kt b/shared/src/commonMain/kotlin/su/reya/coop/nostr/Messaging.kt index 1b86a7b..a3ac909 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/nostr/Messaging.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/nostr/Messaging.kt @@ -73,6 +73,8 @@ class MessageManager(private val nostr: Nostr) { target = ReqTarget.manual(target), id = "gift-wraps" ) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to fetch user messages: ${e.message}", e) } @@ -225,6 +227,8 @@ class MessageManager(private val nostr: Nostr) { // Filter out events without public keys (receivers) ?.filter { it.tags().publicKeys().isNotEmpty() } ?.sortedByDescending { it.createdAt().asSecs() } ?: emptyList() + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to get chat room messages: ${e.message}", e) } @@ -248,6 +252,8 @@ class MessageManager(private val nostr: Nostr) { connectMsgRelays(event) } } + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to fetch relays: ${e.message}", e) } @@ -340,6 +346,8 @@ class MessageManager(private val nostr: Nostr) { } } } + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to send message: ${e.message}", e) } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/nostr/Nostr.kt b/shared/src/commonMain/kotlin/su/reya/coop/nostr/Nostr.kt index e7617d4..9d90f55 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/nostr/Nostr.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/nostr/Nostr.kt @@ -9,9 +9,9 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.first -import kotlinx.coroutines.withTimeoutOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.withTimeoutOrNull import rust.nostr.sdk.AsyncNostrSigner import rust.nostr.sdk.Client import rust.nostr.sdk.ClientBuilder @@ -108,14 +108,6 @@ class Nostr( relays.connectBootstrapRelays() } - suspend fun reconnect() { - relays.reconnect() - } - - suspend fun disconnect() { - relays.disconnect() - } - suspend fun prune() { try { client?.database()?.wipe() diff --git a/shared/src/commonMain/kotlin/su/reya/coop/nostr/ProfileManager.kt b/shared/src/commonMain/kotlin/su/reya/coop/nostr/ProfileManager.kt index f228757..81439d6 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/nostr/ProfileManager.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/nostr/ProfileManager.kt @@ -27,6 +27,7 @@ import rust.nostr.sdk.ReqTarget import rust.nostr.sdk.SendEventTarget import rust.nostr.sdk.SubscribeAutoCloseOptions import rust.nostr.sdk.Timestamp +import kotlin.coroutines.cancellation.CancellationException import kotlin.time.Duration class ProfileManager(private val nostr: Nostr) { @@ -80,6 +81,8 @@ class ProfileManager(private val nostr: Nostr) { val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose) client?.subscribe(target = target, id = "user-metadata", closeOn = opts) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to fetch user metadata: ${e.message}", e) } @@ -92,6 +95,8 @@ class ProfileManager(private val nostr: Nostr) { val relays = RelayManager.BOOTSTRAP_RELAYS.map { RelayUrl.parse(it) } client?.sync(filter, relays) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { println("Failed to sync mutual contacts: ${e.message}") } @@ -174,6 +179,8 @@ class ProfileManager(private val nostr: Nostr) { ) return newMetadata + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to update identity: ${e.message}", e) } @@ -186,6 +193,8 @@ class ProfileManager(private val nostr: Nostr) { val event = client?.database()?.query(filter)?.first() ?: return null Metadata.fromJson(event.content()) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { println("Failed to get latest metadata: ${e.message}") null @@ -208,6 +217,8 @@ class ProfileManager(private val nostr: Nostr) { } return results + } catch (e: CancellationException) { + throw e } catch (e: Exception) { println("Failed to get all cache metadata: ${e.message}") return emptyMap() @@ -232,6 +243,8 @@ class ProfileManager(private val nostr: Nostr) { } client?.subscribe(target = ReqTarget.manual(target), closeOn = opts) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to fetch metadata batch: ${e.message}", e) } @@ -247,6 +260,8 @@ class ProfileManager(private val nostr: Nostr) { target = SendEventTarget.broadcast(), ackPolicy = AckPolicy.none(), ) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to set contact list: ${e.message}", e) } @@ -258,6 +273,8 @@ class ProfileManager(private val nostr: Nostr) { val bodyString: String = response.body() return Nip05Profile.fromJson(address, bodyString) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to fetch profile from address: ${e.message}", e) } @@ -269,6 +286,8 @@ class ProfileManager(private val nostr: Nostr) { val profile = profileFromAddress(httpClient, address) return profile.publicKey() + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to search address: ${e.message}", e) } @@ -304,6 +323,8 @@ class ProfileManager(private val nostr: Nostr) { } return results + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to search nostr: ${e.message}", e) } @@ -323,6 +344,8 @@ class ProfileManager(private val nostr: Nostr) { ) return events?.first()?.createdAt() + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to get latest activity: ${e.message}", e) } @@ -340,6 +363,8 @@ class ProfileManager(private val nostr: Nostr) { val pubkeys = events?.first()?.tags()?.publicKeys() ?: listOf() return pubkeys.contains(pubkey) + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to get mutual contacts: ${e.message}", e) } @@ -361,6 +386,8 @@ class ProfileManager(private val nostr: Nostr) { } return contacts.toSet() + } catch (e: CancellationException) { + throw e } catch (e: Exception) { throw IllegalStateException("Failed to get mutual contacts: ${e.message}", e) } diff --git a/shared/src/commonMain/kotlin/su/reya/coop/repository/ChatRepository.kt b/shared/src/commonMain/kotlin/su/reya/coop/repository/ChatRepository.kt index 6dbe60a..3968af5 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/repository/ChatRepository.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/repository/ChatRepository.kt @@ -51,13 +51,16 @@ class ChatRepository( ) val newEvents = _newEvents.asSharedFlow() - val chatRooms = state.map { it.rooms.values.sortedByDescending { it.createdAt.asSecs() } } + val chatRooms = state + .map { it.rooms.values.sortedByDescending { it.createdAt.asSecs() } } .stateIn(scope, SharingStarted.WhileSubscribed(5000), emptyList()) - val isSyncing = nostr.messages.messageSyncState.map { it.isSyncing } + val isSyncing = nostr.messages.messageSyncState + .map { it.isSyncing } .stateIn(scope, SharingStarted.WhileSubscribed(5000), false) - val isPartialProcessedGiftWrap = state.map { it.isPartialProcessedGiftWrap } + val isPartialProcessedGiftWrap = state + .map { it.isPartialProcessedGiftWrap } .stateIn(scope, SharingStarted.WhileSubscribed(5000), false) init { diff --git a/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/ProfileCache.kt b/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/ProfileCache.kt index 2205d80..420043a 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/ProfileCache.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/ProfileCache.kt @@ -18,7 +18,7 @@ import kotlin.time.Duration.Companion.milliseconds class ProfileCache( private val nostr: Nostr, - private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default, + defaultDispatcher: CoroutineDispatcher = Dispatchers.Default, ) : ErrorHost by createErrorHost() { private val scope = CoroutineScope(SupervisorJob() + defaultDispatcher) private val profiles = MutableStateFlow>>(emptyMap())