From bb1efa523d39bfcf1a1d4e3cc1a39bd3f612ccf4 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Sun, 12 Jul 2026 18:25:05 +0700 Subject: [PATCH] . --- .../kotlin/su/reya/coop/MainActivity.kt | 29 +----------- .../reya/coop/repository/AccountRepository.kt | 27 +++++++----- .../reya/coop/viewmodel/AccountViewModel.kt | 44 ++++++++++++++----- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt index 266d69e..a50c8c2 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt @@ -8,17 +8,12 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts -import androidx.activity.viewModels import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider import kotlinx.coroutines.MainScope import su.reya.coop.nostr.NostrManager import su.reya.coop.repository.AccountRepository import su.reya.coop.repository.ChatRepository import su.reya.coop.repository.MediaRepository -import su.reya.coop.viewmodel.AccountViewModel -import su.reya.coop.viewmodel.ChatViewModel import su.reya.coop.viewmodel.ProfileCache import kotlin.system.exitProcess @@ -42,28 +37,6 @@ class MainActivity : ComponentActivity() { ChatRepository(NostrManager.instance, mediaRepository, scope) } - private val factory by lazy { - object : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { - val result = when { - modelClass.isAssignableFrom(ChatViewModel::class.java) -> ChatViewModel( - chatRepository - ) - - modelClass.isAssignableFrom(AccountViewModel::class.java) -> AccountViewModel( - accountRepository - ) - - else -> throw IllegalArgumentException("Unknown ViewModel class") - } - @Suppress("UNCHECKED_CAST") - return result as T - } - } - } - - private val accountViewModel: AccountViewModel by viewModels { factory } - override fun onCreate(savedInstanceState: Bundle?) { Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> throwable.printStackTrace() @@ -101,7 +74,7 @@ class MainActivity : ComponentActivity() { // Keep the splash screen visible until the signer check is complete splashScreen.setKeepOnScreenCondition { - accountViewModel.state.value.signerRequired == null + accountRepository.state.value.signerRequired == null } setContent { diff --git a/shared/src/commonMain/kotlin/su/reya/coop/repository/AccountRepository.kt b/shared/src/commonMain/kotlin/su/reya/coop/repository/AccountRepository.kt index 940fc06..f9cbb15 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/repository/AccountRepository.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/repository/AccountRepository.kt @@ -9,6 +9,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first @@ -92,9 +94,22 @@ class AccountRepository( init { checkNotificationBannerDismissedStatus() login() + observeSignerState() observeContactList() } + private fun observeSignerState() { + scope.launch { + nostr.signer.publicKeyFlow + .filterNotNull() + .distinctUntilChanged() + .collectLatest { + getUserMetadata() + checkRelayList() + } + } + } + private fun checkNotificationBannerDismissedStatus() { scope.launch { val dismissed = storage.get(KEY_BANNER_DISMISSED) == "true" @@ -119,7 +134,6 @@ class AccountRepository( nostr.setSigner(signer) }.onSuccess { _state.update { it.copy(signerRequired = false) } - onSignerReady() }.onFailure { e -> showError("Login failed: ${e.message}") _state.update { it.copy(signerRequired = true) } @@ -209,7 +223,6 @@ class AccountRepository( val (signer, decryptedSecret) = createSigner(secret, password) nostr.setSigner(signer) - onSignerReady() storage.setSecret(KEY_USER_SIGNER, decryptedSecret ?: secret) _state.update { it.copy(signerRequired = false, isImporting = false) } @@ -247,7 +260,6 @@ class AccountRepository( val uri = "nip55://${result.packageName}/${result.pubkey.toHex()}" nostr.setSigner(signer) - onSignerReady() storage.setSecret(KEY_USER_SIGNER, uri) _state.update { it.copy(signerRequired = false, isImporting = false) } @@ -279,7 +291,6 @@ class AccountRepository( bio = bio, picture = avatarUrl ) - onSignerReady() storage.setSecret(KEY_USER_SIGNER, secret) _state.update { it.copy(signerRequired = false, isImporting = false) } @@ -290,10 +301,6 @@ class AccountRepository( } } - private fun onSignerReady() { - getUserMetadata() - checkRelayList() - } @OptIn(ExperimentalCoroutinesApi::class) private fun currentUserProfileFlow(pubkey: PublicKey) = merge( @@ -308,7 +315,7 @@ class AccountRepository( .map { (p, m) -> Profile(p, m) } ) - fun getUserMetadata() { + private fun getUserMetadata() { scope.launch { nostr.profiles.getUserMetadata() } @@ -448,7 +455,7 @@ class AccountRepository( } @OptIn(ExperimentalCoroutinesApi::class) - fun checkRelayList() { + private fun checkRelayList() { scope.launch { val currentUser = nostr.signer.publicKeyFlow.filterNotNull().first() diff --git a/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AccountViewModel.kt b/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AccountViewModel.kt index f901a8b..999da5e 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AccountViewModel.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AccountViewModel.kt @@ -19,37 +19,57 @@ class AccountViewModel( val currentUserProfile: StateFlow = repository.currentUserProfile val contactList: StateFlow> = repository.contactList val isRelayListEmpty: StateFlow = repository.isRelayListEmpty - val currentUserRelayList: StateFlow> = repository.currentUserRelayList + val currentUserRelayList: StateFlow> = + repository.currentUserRelayList val currentUserMsgRelayList: StateFlow> = repository.currentUserMsgRelayList fun logout(onLogout: () -> Unit = {}) = repository.logout(onLogout) fun dismissNotificationBanner() = repository.dismissNotificationBanner() fun isExternalSignerAvailable() = repository.isExternalSignerAvailable() - fun importIdentity(secret: String, password: String? = null) = repository.importIdentity(secret, password) + fun importIdentity(secret: String, password: String? = null) = + repository.importIdentity(secret, password) + fun connectExternalSigner() = repository.connectExternalSigner() - fun createIdentity(name: String, bio: String?, picture: ByteArray?, contentType: String? = null) = + fun createIdentity( + name: String, + bio: String?, + picture: ByteArray?, + contentType: String? = null + ) = repository.createIdentity(name, bio, picture, contentType) - fun getUserMetadata() = repository.getUserMetadata() - fun updateProfile(name: String? = null, bio: String? = null, picture: ByteArray? = null, contentType: String? = null) = + fun updateProfile( + name: String? = null, + bio: String? = null, + picture: ByteArray? = null, + contentType: String? = null + ) = repository.updateProfile(name, bio, picture, contentType) fun resetInternalState() = repository.resetInternalState() fun addContact(address: String) = repository.addContact(address) fun removeContact(publicKey: PublicKey) = repository.removeContact(publicKey) - fun searchByAddress(query: String, onResult: (PublicKey?) -> Unit) = repository.searchByAddress(query, onResult) - fun searchByNostr(query: String, onResult: (List) -> Unit) = repository.searchByNostr(query, onResult) - fun verifyActivity(pubkey: PublicKey, onResult: (Timestamp?) -> Unit) = repository.verifyActivity(pubkey, onResult) - fun verifyContact(pubkey: PublicKey, onResult: (Boolean) -> Unit) = repository.verifyContact(pubkey, onResult) - fun mutualContacts(pubkey: PublicKey, onResult: (Set) -> Unit) = repository.mutualContacts(pubkey, onResult) - fun checkRelayList() = repository.checkRelayList() + fun searchByAddress(query: String, onResult: (PublicKey?) -> Unit) = + repository.searchByAddress(query, onResult) + + fun searchByNostr(query: String, onResult: (List) -> Unit) = + repository.searchByNostr(query, onResult) + + fun verifyActivity(pubkey: PublicKey, onResult: (Timestamp?) -> Unit) = + repository.verifyActivity(pubkey, onResult) + + fun verifyContact(pubkey: PublicKey, onResult: (Boolean) -> Unit) = + repository.verifyContact(pubkey, onResult) + + fun mutualContacts(pubkey: PublicKey, onResult: (Set) -> Unit) = + repository.mutualContacts(pubkey, onResult) + fun dismissRelayWarning() = repository.dismissRelayWarning() fun refetchMsgRelays() = repository.refetchMsgRelays() fun useDefaultMsgRelayList() = repository.useDefaultMsgRelayList() fun loadCurrentUserRelayList() = repository.loadCurrentUserRelayList() fun addInboxRelay(relay: String) = repository.addInboxRelay(relay) fun addOutboxRelay(relay: String) = repository.addOutboxRelay(relay) - fun removeRelay(relay: String) = repository.removeRelay(relay) fun loadCurrentUserMsgRelayList() = repository.loadCurrentUserMsgRelayList() fun addMsgRelay(relay: String) = repository.addMsgRelay(relay) fun removeMsgRelay(relay: String) = repository.removeMsgRelay(relay)