clean up chat screen

This commit is contained in:
2026-07-15 07:32:39 +07:00
parent 1485a767ed
commit 9c9d9ae882
4 changed files with 57 additions and 53 deletions

View File

@@ -6,11 +6,14 @@ import android.os.Build
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialExpressiveTheme
import androidx.compose.material3.MotionScheme
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.Typography
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
@@ -24,6 +27,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.core.util.Consumer
import androidx.lifecycle.ViewModel
@@ -230,26 +235,34 @@ fun App(
NewIdentityScreen(accountViewModel)
}
entry<Screen.Chat> { key ->
val factory = remember(key) {
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return ChatScreenViewModel(
key.id,
key.screening,
accountRepository,
chatRepository
) as T
val initialRoom = remember(key.id) { chatRepository.getChatRoom(key.id) }
if (initialRoom != null) {
val factory = remember(initialRoom) {
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ChatScreenViewModel(
initialRoom,
key.screening,
accountRepository,
chatRepository
) as T
}
}
}
ChatScreen(
viewModel<ChatScreenViewModel>(
key = key.id.toString(),
factory = factory
),
accountViewModel
)
} else {
// Handle the rare case where the room isn't in DB (e.g., invalid deep link)
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("Room not found")
}
}
ChatScreen(
viewModel<ChatScreenViewModel>(
key = key.id.toString(),
factory = factory
),
accountViewModel
)
}
entry<Screen.NewChat> {
NewChatScreen(accountViewModel, chatViewModel)

View File

@@ -94,12 +94,11 @@ import rust.nostr.sdk.UnsignedEvent
import su.reya.coop.LocalNavigator
import su.reya.coop.LocalProfileCache
import su.reya.coop.LocalSnackbarHostState
import su.reya.coop.Room
import su.reya.coop.RoomUiState
import su.reya.coop.Screen
import su.reya.coop.flow
import su.reya.coop.formatAsGroup
import su.reya.coop.shared.Avatar
import su.reya.coop.uiStateFlow
import su.reya.coop.viewmodel.AccountViewModel
import su.reya.coop.viewmodel.ChatScreenViewModel
@@ -118,25 +117,11 @@ fun ChatScreen(
val scope = rememberCoroutineScope()
val listState = rememberLazyListState()
val id = viewModel.id
val currentUser by viewModel.currentUser.collectAsStateWithLifecycle()
val chatRooms by viewModel.chatRooms.collectAsStateWithLifecycle()
val room by remember(id) { derivedStateOf { chatRooms.firstOrNull { it.id == id } } }
val pubkey = currentUser?.publicKey
// Show empty screen
if (room == null) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Something went wrong.",
style = MaterialTheme.typography.titleMediumEmphasized,
color = MaterialTheme.colorScheme.onSurface
)
}
return
}
val room by viewModel.room.collectAsStateWithLifecycle()
val roomState by room.flow(profileCache, pubkey).collectAsStateWithLifecycle(RoomUiState())
val loading = viewModel.loading
val newOtherMessages = viewModel.newOtherMessages
@@ -146,9 +131,6 @@ fun ChatScreen(
val groupedMessages =
remember { derivedStateOf { messages.groupBy { it.createdAt().formatAsGroup() } } }
val roomState by (room as Room).uiStateFlow(profileCache, currentUser?.publicKey)
.collectAsStateWithLifecycle(RoomUiState())
var text by remember { mutableStateOf("") }
var selectedMessage by remember { mutableStateOf<Pair<MessageModel, Rect>?>(null) }
var replyingTo by remember { mutableStateOf<MessageModel?>(null) }
@@ -193,9 +175,7 @@ fun ChatScreen(
}
}
Box(
modifier = Modifier.fillMaxSize()
) {
Box(modifier = Modifier.fillMaxSize()) {
Scaffold(
modifier = Modifier.blur(blurAmount),
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.union(WindowInsets.ime),
@@ -207,7 +187,7 @@ fun ChatScreen(
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
room?.members?.firstOrNull()?.let { pubkey ->
room.members.firstOrNull()?.let { pubkey ->
navigator.navigate(Screen.Profile(pubkey.toBech32()))
}
}
@@ -265,7 +245,7 @@ fun ChatScreen(
.padding(bottom = innerPadding.calculateBottomPadding())
) {
if (requireScreening) {
room?.let { ScreenerCard(accountViewModel, it) }
ScreenerCard(accountViewModel, room)
}
when (messages.isNotEmpty()) {
@@ -283,8 +263,7 @@ fun ChatScreen(
items = messagesInGroup,
key = { it.ensureId().id()?.toHex()!! }
) { event ->
val model =
rememberMessageModel(event, currentUser?.publicKey)
val model = rememberMessageModel(event, pubkey)
val replyPreview =
remember(model.replyEventIds, messages.size) {
@@ -298,7 +277,9 @@ fun ChatScreen(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
replyPreview?.let { ReplyPreview(it, model.isMine) }
replyPreview?.let {
ReplyPreview(it, model.isMine)
}
ChatMessage(
model = model,
modifier = Modifier.graphicsLayer {