This commit is contained in:
2026-07-13 07:40:02 +07:00
parent bb1efa523d
commit 40da451f4e
4 changed files with 33 additions and 52 deletions

View File

@@ -100,8 +100,8 @@ fun RelayScreen(viewModel: AccountViewModel) {
viewModel.loadCurrentUserMsgRelayList() viewModel.loadCurrentUserMsgRelayList()
} }
val loadedRelayList by viewModel.currentUserRelayList.collectAsStateWithLifecycle() val loadedRelayList by viewModel.userRelayList.collectAsStateWithLifecycle()
val loadedMsgRelayList by viewModel.currentUserMsgRelayList.collectAsStateWithLifecycle() val loadedMsgRelayList by viewModel.userMsgRelayList.collectAsStateWithLifecycle()
LaunchedEffect(loadedRelayList) { LaunchedEffect(loadedRelayList) {
if (loadedRelayList.isNotEmpty()) { if (loadedRelayList.isNotEmpty()) {

View File

@@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChanged 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.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@@ -84,12 +83,11 @@ class AccountRepository(
private val _isRelayListEmpty = MutableStateFlow(false) private val _isRelayListEmpty = MutableStateFlow(false)
val isRelayListEmpty: StateFlow<Boolean> = _isRelayListEmpty.asStateFlow() val isRelayListEmpty: StateFlow<Boolean> = _isRelayListEmpty.asStateFlow()
private val _currentUserRelayList = MutableStateFlow<Map<RelayUrl, RelayMetadata?>>(emptyMap()) private val _userRelayList = MutableStateFlow<Map<RelayUrl, RelayMetadata?>>(emptyMap())
val currentUserRelayList: StateFlow<Map<RelayUrl, RelayMetadata?>> = val userRelayList: StateFlow<Map<RelayUrl, RelayMetadata?>> = _userRelayList.asStateFlow()
_currentUserRelayList.asStateFlow()
private val _currentUserMsgRelayList = MutableStateFlow<List<RelayUrl>>(emptyList()) private val _userMsgRelayList = MutableStateFlow<List<RelayUrl>>(emptyList())
val currentUserMsgRelayList: StateFlow<List<RelayUrl>> = _currentUserMsgRelayList.asStateFlow() val userMsgRelayList: StateFlow<List<RelayUrl>> = _userMsgRelayList.asStateFlow()
init { init {
checkNotificationBannerDismissedStatus() checkNotificationBannerDismissedStatus()
@@ -103,9 +101,22 @@ class AccountRepository(
nostr.signer.publicKeyFlow nostr.signer.publicKeyFlow
.filterNotNull() .filterNotNull()
.distinctUntilChanged() .distinctUntilChanged()
.collectLatest { .collectLatest { pubkey ->
getUserMetadata() // Refresh metadata
checkRelayList() nostr.profiles.getUserMetadata()
// Verify messaging relays exist (wait up to 10s for initial fetch)
val relays = withTimeoutOrNull(10.seconds) {
var list = nostr.relays.getMsgRelays(pubkey)
while (list.isEmpty()) {
delay(500.milliseconds)
list = nostr.relays.getMsgRelays(pubkey)
}
list
} ?: emptyList()
// Automatically update the warning state
_isRelayListEmpty.value = relays.isEmpty()
} }
} }
} }
@@ -315,12 +326,6 @@ class AccountRepository(
.map { (p, m) -> Profile(p, m) } .map { (p, m) -> Profile(p, m) }
) )
private fun getUserMetadata() {
scope.launch {
nostr.profiles.getUserMetadata()
}
}
fun updateProfile( fun updateProfile(
name: String? = null, name: String? = null,
bio: String? = null, bio: String? = null,
@@ -454,24 +459,6 @@ class AccountRepository(
} }
} }
@OptIn(ExperimentalCoroutinesApi::class)
private fun checkRelayList() {
scope.launch {
val currentUser = nostr.signer.publicKeyFlow.filterNotNull().first()
val relays = withTimeoutOrNull(10.seconds) {
var result = nostr.relays.getMsgRelays(currentUser)
while (result.isEmpty()) {
delay(500.milliseconds)
result = nostr.relays.getMsgRelays(currentUser)
}
result
} ?: emptyList()
if (relays.isEmpty()) _isRelayListEmpty.value = true
}
}
fun dismissRelayWarning() { fun dismissRelayWarning() {
_isRelayListEmpty.value = false _isRelayListEmpty.value = false
} }
@@ -499,9 +486,8 @@ class AccountRepository(
fun loadCurrentUserRelayList() { fun loadCurrentUserRelayList() {
scope.launch { scope.launch {
try { try {
val currentUser = val user = nostr.signer.getPublicKeyAsync() ?: throw Exception("User not found")
nostr.signer.getPublicKeyAsync() ?: throw Exception("User not found") _userRelayList.value = nostr.relays.getRelayList(user)
_currentUserRelayList.value = nostr.relays.getRelayList(currentUser)
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }
@@ -563,16 +549,15 @@ class AccountRepository(
fun loadCurrentUserMsgRelayList() { fun loadCurrentUserMsgRelayList() {
scope.launch { scope.launch {
try { try {
val currentUser = val user = nostr.signer.getPublicKeyAsync() ?: throw Exception("User not found")
nostr.signer.getPublicKeyAsync() ?: throw Exception("User not found") _userMsgRelayList.value = nostr.relays.getMsgRelays(user)
_currentUserMsgRelayList.value = nostr.relays.getMsgRelays(currentUser)
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }
} }
} }
private suspend fun currentUserMsgRelayListInternal(): List<RelayUrl> { private suspend fun userLatestMsgRelayList(): List<RelayUrl> {
try { try {
val currentUser = nostr.signer.getPublicKeyAsync() ?: throw Exception("User not found") val currentUser = nostr.signer.getPublicKeyAsync() ?: throw Exception("User not found")
return nostr.relays.getMsgRelays(currentUser) return nostr.relays.getMsgRelays(currentUser)
@@ -586,7 +571,7 @@ class AccountRepository(
scope.launch { scope.launch {
try { try {
val relayUrl = RelayUrl.parse(relay) val relayUrl = RelayUrl.parse(relay)
val relays = currentUserMsgRelayListInternal().toMutableSet() val relays = userLatestMsgRelayList().toMutableSet()
relays.add(relayUrl) relays.add(relayUrl)
nostr.relays.setMsgRelays(relays.toList()) nostr.relays.setMsgRelays(relays.toList())
@@ -600,7 +585,7 @@ class AccountRepository(
scope.launch { scope.launch {
try { try {
val relayUrl = RelayUrl.parse(relay) val relayUrl = RelayUrl.parse(relay)
val relays = currentUserMsgRelayListInternal().toMutableSet() val relays = userLatestMsgRelayList().toMutableSet()
relays.remove(relayUrl) relays.remove(relayUrl)
nostr.relays.setMsgRelays(relays.toList()) nostr.relays.setMsgRelays(relays.toList())

View File

@@ -19,9 +19,8 @@ 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?>> = val userRelayList: StateFlow<Map<RelayUrl, RelayMetadata?>> = repository.userRelayList
repository.currentUserRelayList val userMsgRelayList: StateFlow<List<RelayUrl>> = repository.userMsgRelayList
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()
@@ -35,16 +34,14 @@ class AccountViewModel(
bio: String?, bio: String?,
picture: ByteArray?, picture: ByteArray?,
contentType: String? = null contentType: String? = null
) = ) = repository.createIdentity(name, bio, picture, contentType)
repository.createIdentity(name, bio, picture, contentType)
fun updateProfile( fun updateProfile(
name: String? = null, name: String? = null,
bio: String? = null, bio: String? = null,
picture: ByteArray? = null, picture: ByteArray? = null,
contentType: String? = 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)

View File

@@ -29,7 +29,6 @@ class ChatScreenViewModel(
var loading by mutableStateOf(true) var loading by mutableStateOf(true)
var newOtherMessages by mutableIntStateOf(0) var newOtherMessages by mutableIntStateOf(0)
var requireScreening by mutableStateOf(screening) var requireScreening by mutableStateOf(screening)
val messages = mutableStateListOf<UnsignedEvent>() val messages = mutableStateListOf<UnsignedEvent>()
init { init {