4 Commits

Author SHA1 Message Date
2d830b778f clean up 2026-07-15 17:57:55 +07:00
fcc30157bb Revert "clean up chat screen"
This reverts commit 9c9d9ae882.
2026-07-15 17:02:55 +07:00
43618533a5 improve the profile cache 2026-07-15 08:18:05 +07:00
9c9d9ae882 clean up chat screen 2026-07-15 07:32:39 +07:00
6 changed files with 54 additions and 36 deletions

View File

@@ -69,7 +69,7 @@ android {
minSdk = libs.versions.android.minSdk.get().toInt() minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt() targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1 versionCode = 1
versionName = "0.2.5" versionName = "0.2.4"
} }
packaging { packaging {
resources { resources {

View File

@@ -39,11 +39,12 @@ class MessageManager(private val nostr: Nostr) {
private val client: Client? get() = nostr.client private val client: Client? get() = nostr.client
private val signer: UniversalSigner get() = nostr.signer private val signer: UniversalSigner get() = nostr.signer
val sentEvents: MutableMap<EventId, List<RelayUrl>> = mutableMapOf()
val rumorMap: MutableMap<EventId, EventId> = mutableMapOf()
private val _messageSyncState = MutableStateFlow(MessageSyncState()) private val _messageSyncState = MutableStateFlow(MessageSyncState())
val messageSyncState = _messageSyncState.asStateFlow() val messageSyncState = _messageSyncState.asStateFlow()
val rumorMap: MutableMap<EventId, EventId> = mutableMapOf()
fun updateSyncState(update: (MessageSyncState) -> MessageSyncState) { fun updateSyncState(update: (MessageSyncState) -> MessageSyncState) {
_messageSyncState.update(update) _messageSyncState.update(update)
} }
@@ -332,6 +333,9 @@ class MessageManager(private val nostr: Nostr) {
) )
if (output != null) { if (output != null) {
// Keep track of sent events
sentEvents[output.id] = emptyList()
// Keep track of rumor IDs // Keep track of rumor IDs
val id = rumor.id() ?: throw IllegalStateException("Rumor ID is null") val id = rumor.id() ?: throw IllegalStateException("Rumor ID is null")
rumorMap[id] = output.id rumorMap[id] = output.id

View File

@@ -174,6 +174,8 @@ class Nostr(
when (notification) { when (notification) {
is ClientNotification.Message -> { is ClientNotification.Message -> {
val relayUrl = notification.relayUrl
when (val message = notification.message.asEnum()) { when (val message = notification.message.asEnum()) {
is RelayMessageEnum.EventMsg -> { is RelayMessageEnum.EventMsg -> {
val event = message.event val event = message.event
@@ -227,6 +229,14 @@ class Nostr(
} }
} }
is RelayMessageEnum.Ok -> {
if (messages.sentEvents.containsKey(message.eventId)) {
val currentRelays =
messages.sentEvents[message.eventId] ?: emptyList()
messages.sentEvents[message.eventId] = currentRelays + relayUrl
}
}
else -> { else -> {
/* Ignore other message types */ /* Ignore other message types */
} }

View File

@@ -130,7 +130,7 @@ class RelayManager(private val nostr: Nostr) {
} }
} }
suspend fun setRelayList(relays: Map<RelayUrl, RelayMetadata?>) { suspend fun setRelaylist(relays: Map<RelayUrl, RelayMetadata?>) {
try { try {
val event = EventBuilder.relayList(relays).finalizeAsync(signer) val event = EventBuilder.relayList(relays).finalizeAsync(signer)

View File

@@ -511,7 +511,7 @@ class AccountRepository(
val relays = currentUserRelayListInternal().toMutableMap() val relays = currentUserRelayListInternal().toMutableMap()
relays[relayUrl] = RelayMetadata.WRITE relays[relayUrl] = RelayMetadata.WRITE
nostr.relays.setRelayList(relays) nostr.relays.setRelaylist(relays)
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }
@@ -525,7 +525,7 @@ class AccountRepository(
val relays = currentUserRelayListInternal().toMutableMap() val relays = currentUserRelayListInternal().toMutableMap()
relays[relayUrl] = RelayMetadata.READ relays[relayUrl] = RelayMetadata.READ
nostr.relays.setRelayList(relays) nostr.relays.setRelaylist(relays)
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }
@@ -539,7 +539,7 @@ class AccountRepository(
val relays = currentUserRelayListInternal().toMutableMap() val relays = currentUserRelayListInternal().toMutableMap()
relays.remove(relayUrl) relays.remove(relayUrl)
nostr.relays.setRelayList(relays) nostr.relays.setRelaylist(relays)
} catch (e: Exception) { } catch (e: Exception) {
showError("Error: ${e.message}") showError("Error: ${e.message}")
} }

View File

@@ -85,7 +85,18 @@ class ChatRepository(
// Observe new messages // Observe new messages
launch { launch {
nostr.newEvents.collect { event -> nostr.newEvents.collect { event ->
updateRoomState(event) val roomId = event.roomId()
val existingRoom = _state.value.rooms[roomId]
if (existingRoom == null) {
val currentUser = nostr.signer.getPublicKeyAsync() ?: return@collect
val newRoom = Room.new(event, currentUser)
_state.update { it.copy(rooms = it.rooms + (newRoom.id to newRoom)) }
} else {
updateRoomList(roomId, event)
}
_newEvents.tryEmit(event)
} }
} }
} }
@@ -186,10 +197,9 @@ class ChatRepository(
content = message, content = message,
subject = room.subject, subject = room.subject,
replies = replies, replies = replies,
onRumorCreated = { onRumorCreated = { event ->
scope.launch(defaultDispatcher) { updateRoomList(roomId, event)
updateRoomState(it, roomId) scope.launch(defaultDispatcher) { _newEvents.tryEmit(event) }
}
}, },
) )
} catch (e: Exception) { } catch (e: Exception) {
@@ -216,32 +226,26 @@ class ChatRepository(
} }
} }
private suspend fun updateRoomState(event: UnsignedEvent, roomId: Long = event.roomId()) { fun isMessageSent(id: EventId): Boolean {
val currentUser = nostr.signer.getPublicKeyAsync() ?: return val giftWrapId = nostr.messages.rumorMap[id]
_state.update { currentState -> if (giftWrapId != null) {
val rooms = currentState.rooms.toMutableMap() val isSent = nostr.messages.sentEvents[giftWrapId]?.isNotEmpty() ?: false
val existingRoom = rooms[roomId] return isSent
} else {
if (existingRoom == null) { return false
// New room discovery
val newRoom = Room.new(event, currentUser, roomId)
rooms[newRoom.id] = newRoom
} else if (event.createdAt().asSecs() >= existingRoom.createdAt.asSecs()) {
// Only update preview if message is newer (handles sync/late arrivals)
rooms[roomId] = existingRoom.copy(
lastMessage = event.content(),
createdAt = event.createdAt()
)
} else {
// Don't update the room list state for older messages
return@update currentState
}
currentState.copy(rooms = rooms)
} }
}
// Notify subscribers about the new event (for the active chat screen) private fun updateRoomList(roomId: Long, newMessage: UnsignedEvent) {
_newEvents.tryEmit(event) _state.update { currentState ->
val room = currentState.rooms[roomId] ?: return@update currentState
val updatedRoom = room.copy(
lastMessage = newMessage.content(),
createdAt = newMessage.createdAt()
)
currentState.copy(rooms = currentState.rooms + (roomId to updatedRoom))
}
} }
fun resetInternalState() { fun resetInternalState() {