This commit is contained in:
2026-07-12 18:25:05 +07:00
parent 2d9bcab946
commit bb1efa523d
3 changed files with 50 additions and 50 deletions

View File

@@ -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 <T : ViewModel> create(modelClass: Class<T>): 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 {

View File

@@ -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()

View File

@@ -19,37 +19,57 @@ class AccountViewModel(
val currentUserProfile: StateFlow<Profile?> = repository.currentUserProfile
val contactList: StateFlow<Set<PublicKey>> = repository.contactList
val isRelayListEmpty: StateFlow<Boolean> = repository.isRelayListEmpty
val currentUserRelayList: StateFlow<Map<RelayUrl, RelayMetadata?>> = repository.currentUserRelayList
val currentUserRelayList: StateFlow<Map<RelayUrl, RelayMetadata?>> =
repository.currentUserRelayList
val currentUserMsgRelayList: StateFlow<List<RelayUrl>> = 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<PublicKey>) -> 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<PublicKey>) -> 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<PublicKey>) -> 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<PublicKey>) -> 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)