Compare commits

..
2 Commits
Author SHA1 Message Date
reya 7009dbf692 chore: update bootstrap relay set 2026-08-03 15:24:52 +07:00
reya 9a2bd3816f chore: improve message reply (#50)
Reviewed-on: https://git.reya.su/reya/coop-mobile/pulls/50
2026-07-22 00:55:06 +00:00
2 changed files with 50 additions and 13 deletions
@@ -90,6 +90,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jetbrains.compose.resources.painterResource
import rust.nostr.sdk.EventId
import rust.nostr.sdk.UnsignedEvent
import su.reya.coop.LocalNavigator
import su.reya.coop.LocalProfileCache
@@ -161,6 +162,29 @@ fun ChatScreen(
label = "blurAnimation"
)
val goToMessage = { eventId: EventId? ->
if (eventId != null) {
scope.launch {
var targetIndex = -1
var currentIndex = 0
for (group in groupedMessages.value) {
val msgInGroup = group.value
val idx = msgInGroup.indexOfFirst { it.id() == eventId }
if (idx != -1) {
targetIndex = currentIndex + idx
break
}
currentIndex += msgInGroup.size + 1
}
if (targetIndex != -1) {
listState.animateScrollToItem(targetIndex)
}
}
}
}
val sendFile = { uri: Uri ->
scope.launch {
// Read file on IO dispatcher
@@ -196,9 +220,7 @@ fun ChatScreen(
}
}
Box(
modifier = Modifier.fillMaxSize()
) {
Box(modifier = Modifier.fillMaxSize()) {
Scaffold(
modifier = Modifier.blur(blurAmount),
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.union(WindowInsets.ime),
@@ -303,7 +325,13 @@ fun ChatScreen(
.animateItem(),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
replyPreview?.let { ReplyPreview(it, model.isMine) }
replyPreview?.let { previewEvent ->
ReplyPreview(
event = previewEvent,
isMine = model.isMine,
onClick = { goToMessage(previewEvent.id()) }
)
}
ChatMessage(
model = model,
modifier = Modifier.graphicsLayer {
@@ -394,8 +422,9 @@ fun ChatScreen(
value = text,
onValueChange = { text = it },
onSend = {
viewModel.sendMessage(text)
viewModel.sendMessage(text, replyingTo?.id)
text = ""
replyingTo = null
},
onUpload = {
fileLauncher.launch("image/*")
@@ -544,7 +573,11 @@ private fun ReplyBox(model: MessageModel, onDismiss: () -> Unit) {
}
@Composable
private fun ReplyPreview(event: UnsignedEvent, isMine: Boolean = false) {
private fun ReplyPreview(
event: UnsignedEvent,
isMine: Boolean = false,
onClick: () -> Unit
) {
val profileCache = LocalProfileCache.current
val profileFlow = remember(event) { profileCache.getMetadata(event.author()) }
val profile by profileFlow.collectAsStateWithLifecycle()
@@ -560,7 +593,9 @@ private fun ReplyPreview(event: UnsignedEvent, isMine: Boolean = false) {
contentAlignment = if (isMine) Alignment.CenterEnd else Alignment.CenterStart
) {
Surface(
modifier = Modifier.widthIn(max = 280.dp),
modifier = Modifier
.widthIn(max = 280.dp)
.clickable(onClick = onClick),
color = MaterialTheme.colorScheme.tertiaryContainer,
shape = bubbleShape,
) {
@@ -568,13 +603,13 @@ private fun ReplyPreview(event: UnsignedEvent, isMine: Boolean = false) {
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
Text(
text = profile?.name ?: "Unknown",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onTertiaryContainer.copy(
alpha = 0.6f
),
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onTertiaryContainer,
)
Text(
text = event.content(),
@@ -22,13 +22,15 @@ import kotlin.time.Duration
class RelayManager(private val nostr: Nostr) {
companion object {
val BOOTSTRAP_RELAYS = listOf(
"wss://relay.primal.net",
"wss://relay.ditto.pub",
"wss://user.kindpag.es",
"wss://relay.primal.net",
"wss://relay.nostr.net",
"wss://profiles.nostr1.com",
)
val INDEXER_RELAY = listOf(
"wss://indexer.coracle.social",
"wss://user.kindpag.es",
)
val ALL_RELAYS = BOOTSTRAP_RELAYS + INDEXER_RELAY