add check sent message
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package su.reya.coop.screens
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
@@ -240,7 +241,17 @@ fun ChatMessage(
|
||||
color = containerColor,
|
||||
contentColor = contentColor,
|
||||
shape = bubbleShape,
|
||||
modifier = Modifier.widthIn(max = 280.dp)
|
||||
modifier = Modifier
|
||||
.widthIn(max = 280.dp)
|
||||
.clickable(
|
||||
onClick = {
|
||||
val id = rumor.id()
|
||||
if (id != null) {
|
||||
val sent = viewModel.isMessageSent(id)
|
||||
println("Sent: $sent")
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = rumor.content(),
|
||||
|
||||
@@ -66,6 +66,10 @@ class Nostr {
|
||||
private set
|
||||
var msgRelayList: Map<PublicKey, List<RelayUrl>> = emptyMap()
|
||||
private set
|
||||
var sentEvents: MutableMap<EventId, List<RelayUrl>> = mutableMapOf()
|
||||
private set
|
||||
var rumorMap: MutableMap<EventId, EventId> = mutableMapOf()
|
||||
private set
|
||||
|
||||
suspend fun init(dbPath: String) {
|
||||
try {
|
||||
@@ -94,6 +98,7 @@ class Nostr {
|
||||
.build()
|
||||
|
||||
// Bootstrap relays
|
||||
client?.addRelay(RelayUrl.parse("wss://relay.damus.io"))
|
||||
client?.addRelay(RelayUrl.parse("wss://relay.primal.net"))
|
||||
client?.addRelay(RelayUrl.parse("wss://user.kindpag.es"))
|
||||
client?.addRelay(RelayUrl.parse("wss://purplepag.es"))
|
||||
@@ -334,6 +339,13 @@ class Nostr {
|
||||
}
|
||||
}
|
||||
|
||||
is RelayMessageEnum.Ok -> {
|
||||
if (sentEvents.containsKey(message.eventId)) {
|
||||
val currentRelays = sentEvents[message.eventId] ?: emptyList()
|
||||
sentEvents[message.eventId] = currentRelays + relayUrl
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
/* Ignore other message types */
|
||||
}
|
||||
@@ -495,7 +507,7 @@ class Nostr {
|
||||
|
||||
client?.sendEvent(
|
||||
event = metadataEvent,
|
||||
target = SendEventTarget.toNip65(),
|
||||
target = SendEventTarget.broadcast(),
|
||||
ackPolicy = AckPolicy.none()
|
||||
)
|
||||
|
||||
@@ -515,7 +527,7 @@ class Nostr {
|
||||
|
||||
suspend fun fetchMetadataBatch(keys: List<PublicKey>) {
|
||||
try {
|
||||
val limit = keys.size.toULong();
|
||||
val limit = keys.size.toULong() * 4u;
|
||||
val opts = SubscribeAutoCloseOptions().exitPolicy(ReqExitPolicy.ExitOnEose)
|
||||
|
||||
// Construct a filter for metadata events
|
||||
@@ -528,8 +540,10 @@ class Nostr {
|
||||
val target =
|
||||
ReqTarget.manual(
|
||||
mapOf(
|
||||
RelayUrl.parse("wss://purplepag.es") to listOf(filter),
|
||||
RelayUrl.parse("wss://user.kindpag.es") to listOf(filter),
|
||||
RelayUrl.parse("wss://relay.primal.net") to listOf(filter)
|
||||
RelayUrl.parse("wss://relay.primal.net") to listOf(filter),
|
||||
RelayUrl.parse("wss://relay.damus.io") to listOf(filter),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -550,37 +564,31 @@ class Nostr {
|
||||
val events = client?.database()?.query(filter)
|
||||
|
||||
// Collect rooms
|
||||
val rooms: MutableSet<Room> = mutableSetOf()
|
||||
val roomsMap: MutableMap<Long, Room> = mutableMapOf()
|
||||
|
||||
events
|
||||
?.toVec()
|
||||
?.map { UnsignedEvent.fromJson(it.content()) }
|
||||
?.filter { it.tags().publicKeys().isNotEmpty() }
|
||||
?.sortedByDescending { it.createdAt().asSecs() }
|
||||
?.forEach { event ->
|
||||
val room = Room.new(rumor = event, userPubkey = userPubkey)
|
||||
val newRoom = Room.new(rumor = event, userPubkey = userPubkey)
|
||||
val existingRoom = roomsMap[newRoom.id]
|
||||
|
||||
// Check if the room already exists
|
||||
if (rooms.contains(room)) {
|
||||
room.setCreatedAt(room.createdAt)
|
||||
room.setLastMessage(room.lastMessage)
|
||||
}
|
||||
|
||||
if (existingRoom == null || newRoom.createdAt.asSecs() > existingRoom.createdAt.asSecs()) {
|
||||
val filter =
|
||||
Filter().kind(kind).author(userPubkey).pubkeys(room.members.toList());
|
||||
Filter().kind(kind).author(userPubkey).pubkeys(newRoom.members.toList())
|
||||
|
||||
// Check if the user is interacting with the room's members
|
||||
val isOngoing = client?.database()?.query(filter)?.isEmpty() == false;
|
||||
// Determine if it's an ongoing room
|
||||
val isOngoing = client?.database()?.query(filter)?.isEmpty() == false
|
||||
|
||||
// Set the room kind based on interaction status
|
||||
if (isOngoing) {
|
||||
room.setKind(RoomKind.Ongoing)
|
||||
// Append room to map
|
||||
roomsMap[newRoom.id] =
|
||||
if (isOngoing) newRoom.copy(kind = RoomKind.Ongoing) else newRoom
|
||||
}
|
||||
}
|
||||
|
||||
rooms.add(room)
|
||||
}
|
||||
|
||||
return rooms
|
||||
return roomsMap.values.toSet()
|
||||
} catch (e: Exception) {
|
||||
println("Failed to get chat rooms: ${e.message}")
|
||||
return null
|
||||
@@ -625,7 +633,7 @@ class Nostr {
|
||||
content: String,
|
||||
subject: String? = null,
|
||||
replies: List<EventId> = emptyList(),
|
||||
onNewMessage: ((UnsignedEvent) -> Unit)? = null
|
||||
onRumorCreated: ((UnsignedEvent) -> Unit)? = null,
|
||||
) {
|
||||
try {
|
||||
val currentUser =
|
||||
@@ -664,7 +672,7 @@ class Nostr {
|
||||
|
||||
// Emit the rumor to the chat screen
|
||||
if (receiver == currentUser) {
|
||||
onNewMessage?.invoke(rumor)
|
||||
onRumorCreated?.invoke(rumor)
|
||||
}
|
||||
|
||||
// Construct the gift wrap event
|
||||
@@ -678,12 +686,19 @@ class Nostr {
|
||||
)
|
||||
|
||||
// Send the event to receiver's NIP-17 relays
|
||||
client?.sendEvent(
|
||||
val output = client?.sendEvent(
|
||||
event = gift,
|
||||
target = SendEventTarget.toNip17(),
|
||||
ackPolicy = AckPolicy.none(),
|
||||
authenticationTimeout = Duration.parse("2s")
|
||||
)
|
||||
|
||||
if (output != null) {
|
||||
sentEvents[output.id] = emptyList()
|
||||
if (rumor.id() != null) {
|
||||
rumorMap[rumor.id()!!] = output.id
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw IllegalStateException("Failed to send message: ${e.message}", e)
|
||||
|
||||
@@ -24,6 +24,7 @@ import rust.nostr.sdk.Metadata
|
||||
import rust.nostr.sdk.NostrConnect
|
||||
import rust.nostr.sdk.NostrConnectUri
|
||||
import rust.nostr.sdk.PublicKey
|
||||
import rust.nostr.sdk.RelayUrl
|
||||
import rust.nostr.sdk.Tag
|
||||
import rust.nostr.sdk.UnsignedEvent
|
||||
import su.reya.coop.blossom.BlossomClient
|
||||
@@ -50,6 +51,9 @@ class NostrViewModel(
|
||||
private val _newEvents = MutableSharedFlow<UnsignedEvent>(extraBufferCapacity = 100)
|
||||
val newEvents = _newEvents.asSharedFlow()
|
||||
|
||||
private val _sentReports = MutableStateFlow<Map<EventId, List<RelayUrl>>>(emptyMap())
|
||||
val sentReport = _sentReports.asSharedFlow()
|
||||
|
||||
private val _errorEvents = Channel<String>(Channel.BUFFERED)
|
||||
val errorEvents = _errorEvents.receiveAsFlow()
|
||||
|
||||
@@ -104,6 +108,7 @@ class NostrViewModel(
|
||||
if (batch.size >= 10 || (now - lastFlushTime) >= timeout || nextKey == null) {
|
||||
val keysToRequest = batch.toList()
|
||||
batch.clear()
|
||||
|
||||
nostr.fetchMetadataBatch(keysToRequest)
|
||||
}
|
||||
}
|
||||
@@ -366,11 +371,10 @@ class NostrViewModel(
|
||||
content = message,
|
||||
subject = room.subject,
|
||||
replies = replies,
|
||||
onNewMessage = { event ->
|
||||
viewModelScope.launch {
|
||||
_newEvents.emit(event)
|
||||
}
|
||||
}
|
||||
onRumorCreated = { event ->
|
||||
updateRoomList(roomId, event)
|
||||
viewModelScope.launch { _newEvents.emit(event) }
|
||||
},
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
showError("Error: ${e.message}")
|
||||
@@ -378,6 +382,27 @@ class NostrViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun isMessageSent(id: EventId): Boolean {
|
||||
val giftWrapId = nostr.rumorMap[id]
|
||||
|
||||
if (giftWrapId != null) {
|
||||
val isSent = nostr.sentEvents[giftWrapId]?.isNotEmpty() ?: false
|
||||
return isSent
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateRoomList(roomId: Long, newMessage: UnsignedEvent) {
|
||||
_chatRooms.value = _chatRooms.value.map { room ->
|
||||
if (room.id == roomId) {
|
||||
room.copy(lastMessage = newMessage.content(), createdAt = newMessage.createdAt())
|
||||
} else {
|
||||
room
|
||||
}
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
suspend fun searchByAddress(query: String): PublicKey? {
|
||||
try {
|
||||
return nostr.searchByAddress(query)
|
||||
|
||||
@@ -29,14 +29,6 @@ data class Room(
|
||||
val kind: RoomKind = RoomKind.default(),
|
||||
val lastMessage: String? = null
|
||||
) : Comparable<Room> {
|
||||
override fun hashCode(): Int = id.hashCode()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Room) return false
|
||||
return id == other.id
|
||||
}
|
||||
|
||||
override fun compareTo(other: Room): Int {
|
||||
return this.createdAt.asSecs().compareTo(other.createdAt.asSecs())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user