chore: clean up codebase #42

Merged
reya merged 6 commits from cleanup into master 2026-07-13 01:04:16 +00:00
3 changed files with 50 additions and 50 deletions
Showing only changes of commit bb1efa523d - Show all commits

View File

@@ -8,17 +8,12 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import su.reya.coop.nostr.NostrManager import su.reya.coop.nostr.NostrManager
import su.reya.coop.repository.AccountRepository import su.reya.coop.repository.AccountRepository
import su.reya.coop.repository.ChatRepository import su.reya.coop.repository.ChatRepository
import su.reya.coop.repository.MediaRepository 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 su.reya.coop.viewmodel.ProfileCache
import kotlin.system.exitProcess import kotlin.system.exitProcess
@@ -42,28 +37,6 @@ class MainActivity : ComponentActivity() {
ChatRepository(NostrManager.instance, mediaRepository, scope) 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?) { override fun onCreate(savedInstanceState: Bundle?) {
Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
throwable.printStackTrace() throwable.printStackTrace()
@@ -101,7 +74,7 @@ class MainActivity : ComponentActivity() {
// Keep the splash screen visible until the signer check is complete // Keep the splash screen visible until the signer check is complete
splashScreen.setKeepOnScreenCondition { splashScreen.setKeepOnScreenCondition {
accountViewModel.state.value.signerRequired == null accountRepository.state.value.signerRequired == null
} }
setContent { setContent {

View File

@@ -9,6 +9,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@@ -92,9 +94,22 @@ class AccountRepository(
init { init {
checkNotificationBannerDismissedStatus() checkNotificationBannerDismissedStatus()
login() login()
observeSignerState()
observeContactList() observeContactList()
} }
private fun observeSignerState() {
scope.launch {
nostr.signer.publicKeyFlow
.filterNotNull()
.distinctUntilChanged()
.collectLatest {
getUserMetadata()
checkRelayList()
}
}
}
private fun checkNotificationBannerDismissedStatus() { private fun checkNotificationBannerDismissedStatus() {
scope.launch { scope.launch {
val dismissed = storage.get(KEY_BANNER_DISMISSED) == "true" val dismissed = storage.get(KEY_BANNER_DISMISSED) == "true"
@@ -119,7 +134,6 @@ class AccountRepository(
nostr.setSigner(signer) nostr.setSigner(signer)
}.onSuccess { }.onSuccess {
_state.update { it.copy(signerRequired = false) } _state.update { it.copy(signerRequired = false) }
onSignerReady()
}.onFailure { e -> }.onFailure { e ->
showError("Login failed: ${e.message}") showError("Login failed: ${e.message}")
_state.update { it.copy(signerRequired = true) } _state.update { it.copy(signerRequired = true) }
@@ -209,7 +223,6 @@ class AccountRepository(
val (signer, decryptedSecret) = createSigner(secret, password) val (signer, decryptedSecret) = createSigner(secret, password)
nostr.setSigner(signer) nostr.setSigner(signer)
onSignerReady()
storage.setSecret(KEY_USER_SIGNER, decryptedSecret ?: secret) storage.setSecret(KEY_USER_SIGNER, decryptedSecret ?: secret)
_state.update { it.copy(signerRequired = false, isImporting = false) } _state.update { it.copy(signerRequired = false, isImporting = false) }
@@ -247,7 +260,6 @@ class AccountRepository(
val uri = "nip55://${result.packageName}/${result.pubkey.toHex()}" val uri = "nip55://${result.packageName}/${result.pubkey.toHex()}"
nostr.setSigner(signer) nostr.setSigner(signer)
onSignerReady()
storage.setSecret(KEY_USER_SIGNER, uri) storage.setSecret(KEY_USER_SIGNER, uri)
_state.update { it.copy(signerRequired = false, isImporting = false) } _state.update { it.copy(signerRequired = false, isImporting = false) }
@@ -279,7 +291,6 @@ class AccountRepository(
bio = bio, bio = bio,
picture = avatarUrl picture = avatarUrl
) )
onSignerReady()
storage.setSecret(KEY_USER_SIGNER, secret) storage.setSecret(KEY_USER_SIGNER, secret)
_state.update { it.copy(signerRequired = false, isImporting = false) } _state.update { it.copy(signerRequired = false, isImporting = false) }
@@ -290,10 +301,6 @@ class AccountRepository(
} }
} }
private fun onSignerReady() {
getUserMetadata()
checkRelayList()
}
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private fun currentUserProfileFlow(pubkey: PublicKey) = merge( private fun currentUserProfileFlow(pubkey: PublicKey) = merge(
@@ -308,7 +315,7 @@ class AccountRepository(
.map { (p, m) -> Profile(p, m) } .map { (p, m) -> Profile(p, m) }
) )
fun getUserMetadata() { private fun getUserMetadata() {
scope.launch { scope.launch {
nostr.profiles.getUserMetadata() nostr.profiles.getUserMetadata()
} }
@@ -448,7 +455,7 @@ class AccountRepository(
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
fun checkRelayList() { private fun checkRelayList() {
scope.launch { scope.launch {
val currentUser = nostr.signer.publicKeyFlow.filterNotNull().first() val currentUser = nostr.signer.publicKeyFlow.filterNotNull().first()

View File

@@ -19,37 +19,57 @@ class AccountViewModel(
val currentUserProfile: StateFlow<Profile?> = repository.currentUserProfile val currentUserProfile: StateFlow<Profile?> = repository.currentUserProfile
val contactList: StateFlow<Set<PublicKey>> = repository.contactList val contactList: StateFlow<Set<PublicKey>> = repository.contactList
val isRelayListEmpty: StateFlow<Boolean> = repository.isRelayListEmpty 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 val currentUserMsgRelayList: StateFlow<List<RelayUrl>> = repository.currentUserMsgRelayList
fun logout(onLogout: () -> Unit = {}) = repository.logout(onLogout) fun logout(onLogout: () -> Unit = {}) = repository.logout(onLogout)
fun dismissNotificationBanner() = repository.dismissNotificationBanner() fun dismissNotificationBanner() = repository.dismissNotificationBanner()
fun isExternalSignerAvailable() = repository.isExternalSignerAvailable() 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 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) repository.createIdentity(name, bio, picture, contentType)
fun getUserMetadata() = repository.getUserMetadata() fun updateProfile(
fun updateProfile(name: String? = null, bio: String? = null, picture: ByteArray? = null, contentType: String? = null) = name: String? = null,
bio: String? = null,
picture: ByteArray? = null,
contentType: String? = null
) =
repository.updateProfile(name, bio, picture, contentType) repository.updateProfile(name, bio, picture, contentType)
fun resetInternalState() = repository.resetInternalState() fun resetInternalState() = repository.resetInternalState()
fun addContact(address: String) = repository.addContact(address) fun addContact(address: String) = repository.addContact(address)
fun removeContact(publicKey: PublicKey) = repository.removeContact(publicKey) fun removeContact(publicKey: PublicKey) = repository.removeContact(publicKey)
fun searchByAddress(query: String, onResult: (PublicKey?) -> Unit) = repository.searchByAddress(query, onResult) fun searchByAddress(query: String, onResult: (PublicKey?) -> Unit) =
fun searchByNostr(query: String, onResult: (List<PublicKey>) -> Unit) = repository.searchByNostr(query, onResult) repository.searchByAddress(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 searchByNostr(query: String, onResult: (List<PublicKey>) -> Unit) =
fun mutualContacts(pubkey: PublicKey, onResult: (Set<PublicKey>) -> Unit) = repository.mutualContacts(pubkey, onResult) repository.searchByNostr(query, onResult)
fun checkRelayList() = repository.checkRelayList()
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 dismissRelayWarning() = repository.dismissRelayWarning()
fun refetchMsgRelays() = repository.refetchMsgRelays() fun refetchMsgRelays() = repository.refetchMsgRelays()
fun useDefaultMsgRelayList() = repository.useDefaultMsgRelayList() fun useDefaultMsgRelayList() = repository.useDefaultMsgRelayList()
fun loadCurrentUserRelayList() = repository.loadCurrentUserRelayList() fun loadCurrentUserRelayList() = repository.loadCurrentUserRelayList()
fun addInboxRelay(relay: String) = repository.addInboxRelay(relay) fun addInboxRelay(relay: String) = repository.addInboxRelay(relay)
fun addOutboxRelay(relay: String) = repository.addOutboxRelay(relay) fun addOutboxRelay(relay: String) = repository.addOutboxRelay(relay)
fun removeRelay(relay: String) = repository.removeRelay(relay)
fun loadCurrentUserMsgRelayList() = repository.loadCurrentUserMsgRelayList() fun loadCurrentUserMsgRelayList() = repository.loadCurrentUserMsgRelayList()
fun addMsgRelay(relay: String) = repository.addMsgRelay(relay) fun addMsgRelay(relay: String) = repository.addMsgRelay(relay)
fun removeMsgRelay(relay: String) = repository.removeMsgRelay(relay) fun removeMsgRelay(relay: String) = repository.removeMsgRelay(relay)