Show LocalChatMessage.kt instead of localChatRoom on chat detail message list

This commit is contained in:
Kgothatso Ngako
2026-06-02 00:27:16 +02:00
parent 740f42b522
commit d1f0a60826
7 changed files with 135 additions and 84 deletions

View File

@@ -2,6 +2,7 @@ package ac.cord.auxiliary.compose.database.dao
import ac.cord.auxiliary.compose.database.model.ChatMessage
import ac.cord.auxiliary.compose.database.model.Relay
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatMessage
import androidx.room3.Dao
import androidx.room3.Query
import androidx.room3.Upsert
@@ -10,7 +11,10 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface ChatMessageDao {
@Query("SELECT * FROM ChatMessage WHERE chatRoomId = :chatRoomId")
fun observeChatMessagesByChatRoomId(chatRoomId: String): Flow<List<ChatMessage>>
fun observeChatMessagesByChatRoomId(chatRoomId: String): Flow<List<LocalChatMessage>>
@Query("SELECT * FROM ChatMessage WHERE chatRoomId = :chatRoomId")
fun getChatMessagesByChatRoomId(chatRoomId: String): List<LocalChatMessage>
@Upsert
suspend fun upsert(chatMessage: ChatMessage)

View File

@@ -0,0 +1,15 @@
package ac.cord.auxiliary.compose.database.model.intermdiate
import ac.cord.auxiliary.compose.database.model.ChatMessage
import ac.cord.auxiliary.compose.database.model.ChatRoom
import ac.cord.auxiliary.compose.database.model.Mention
import ac.cord.auxiliary.compose.database.model.Participant
import ac.cord.auxiliary.compose.database.model.Post
import ac.cord.auxiliary.compose.database.model.Profile
import androidx.room3.Embedded
import androidx.room3.Relation
data class LocalChatMessage(
@Embedded val chatMessage: ChatMessage,
)

View File

@@ -2,10 +2,12 @@ package ac.cord.auxiliary.compose.database.repository
import ac.cord.auxiliary.compose.database.AuxDatabase
import ac.cord.auxiliary.compose.database.model.ChatRoom
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatMessage
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatRoom
import ac.cord.auxiliary.compose.repository.ChatRepository
import co.touchlab.kermit.Logger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
class DatabaseChatRepository(
private val database: AuxDatabase,
@@ -21,6 +23,15 @@ class DatabaseChatRepository(
return database.chatRoomDao().findChatRoomById(id)
}
override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<LocalChatMessage> {
return database.chatMessageDao().getChatMessagesByChatRoomId(chatRoomId)
}
override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<LocalChatMessage>> {
return database.chatMessageDao().observeChatMessagesByChatRoomId(chatRoomId)
}
override suspend fun getOrCreateChatRoom(publicKey: String, defaultSubject: String?): LocalChatRoom? = try {
return database.nostrNip17Dao().getOrCreateChatRoom(
publicKey,

View File

@@ -1,13 +1,20 @@
package ac.cord.auxiliary.compose.repository
import ac.cord.auxiliary.compose.database.model.ChatRoom
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatMessage
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatRoom
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
interface ChatRepository {
suspend fun getChatRoomListByPublicKey(publicKey: String): List<LocalChatRoom>
suspend fun getChatRoomByIdentifier(id: String): LocalChatRoom?
suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<LocalChatMessage>
suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<LocalChatMessage>>
suspend fun getOrCreateChatRoom(publicKey: String, defaultSubject: String? = null): LocalChatRoom?
fun updateChatRoomSubject(publicKey: String, subject: String): ChatRoom?
@@ -22,6 +29,15 @@ interface ChatRepository {
return null
}
override suspend fun getChatMessageListByChatRoomId(chatRoomId: String): List<LocalChatMessage> {
return emptyList()
}
override suspend fun observeChatMessageListByChatRoomId(chatRoomId: String): Flow<List<LocalChatMessage>> {
return flow {
}
}
override suspend fun getOrCreateChatRoom(publicKey: String, defaultSubject: String?): LocalChatRoom? {
return null
}

View File

@@ -56,8 +56,11 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.key
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -132,9 +135,7 @@ fun ChatRoomDetailScreen(
modifier = Modifier.weight(1f).fillMaxWidth()
) {
key(true) {
chatRoomDetailMessageListViewModel.RenderMessages(
onNavigateToDirectMessageDetail = {}
)
chatRoomDetailMessageListViewModel.RenderMessages()
}
}
@@ -193,54 +194,54 @@ fun ChatRoomDetailScreen(
)
}
Row(
modifier = Modifier.padding(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
IconButton(
onClick = {
}
) {
Icon(
Icons.Default.InsertEmoticon,
contentDescription = "Add emoji"
)
}
IconButton(
onClick = {
}
) {
Icon(
Icons.Default.AlternateEmail,
contentDescription = "Mention profile"
)
}
IconButton(
onClick = {
}
) {
Icon(
Icons.Default.Collections,
contentDescription = "Attach media"
)
}
IconButton(
onClick = {
}
) {
Icon(
Icons.Default.LocationOn,
contentDescription = "Send location"
)
}
}
// Row(
// modifier = Modifier.padding(4.dp),
// horizontalArrangement = Arrangement.spacedBy(4.dp)
// ) {
// IconButton(
// onClick = {
//
// }
// ) {
// Icon(
// Icons.Default.InsertEmoticon,
// contentDescription = "Add emoji"
// )
// }
//
// IconButton(
// onClick = {
//
// }
// ) {
// Icon(
// Icons.Default.AlternateEmail,
// contentDescription = "Mention profile"
// )
// }
//
// IconButton(
// onClick = {
//
// }
// ) {
// Icon(
// Icons.Default.Collections,
// contentDescription = "Attach media"
// )
// }
//
// IconButton(
// onClick = {
//
// }
// ) {
// Icon(
// Icons.Default.LocationOn,
// contentDescription = "Send location"
// )
// }
// }
}
}
}

View File

@@ -34,6 +34,7 @@ import androidx.lifecycle.viewmodel.viewModelFactory
import co.touchlab.kermit.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
class ChatRoomDetailMessageListViewModel(
@@ -55,12 +56,12 @@ class ChatRoomDetailMessageListViewModel(
fun observeChatRoomFeed() {
logger.d("observeChatRoomFeed")
viewModelScope.launch(Dispatchers.IO) {
chatRepository.getChatRoomListByPublicKey(
chatRepository.observeChatMessageListByChatRoomId(
localChatRoom.chatRoom.userPublicKey
).let { chatRooms ->
logger.d("ChatRoomList: $chatRooms")
).distinctUntilChanged().collect { chatMessages ->
logger.d("getChatMessageListByChatRoomId: $chatMessages")
chatRoomDetailMessageListUIState = ChatRoomDetailMessageListUIState.Loaded(
chatRoomList = chatRooms
chatMessageList = chatMessages
)
}
}
@@ -89,9 +90,8 @@ class ChatRoomDetailMessageListViewModel(
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun RenderMessages(
onNavigateToDirectMessageDetail: (Route) -> Unit
) {
fun RenderMessages() {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
@@ -111,52 +111,56 @@ class ChatRoomDetailMessageListViewModel(
}
}
is ChatRoomDetailMessageListUIState.Loaded -> {
Spacer(
modifier = Modifier.weight(1f)
)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
if (chatRoomDetailMessageListUIState.chatRoomList.isEmpty()) {
if (chatRoomDetailMessageListUIState.chatMessageList.isEmpty()) {
Spacer(
modifier = Modifier.height(20.dp)
)
Text(
text = "No messages. Go to a profile and send them a message."
modifier = Modifier.padding(20.dp),
text = "Currently no messages have been shared.\nBreak the ice.",
textAlign = TextAlign.Center
)
Spacer(
modifier = Modifier.height(20.dp)
)
} else {
LazyColumn(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth().padding(5.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
reverseLayout = true
) {
items(
items = chatRoomDetailMessageListUIState.chatRoomList,
key = { it.chatRoom.id }
) { localChatRoom ->
items = chatRoomDetailMessageListUIState.chatMessageList,
key = { it.chatMessage.id }
) { localChatMessage ->
Card(
modifier = Modifier.fillMaxWidth(),
onClick = {
onNavigateToDirectMessageDetail.invoke(
ChatRoomDetailRoute(
directMessageIdentifier = localChatRoom.chatRoom.id
)
)
}
) {
Column(
modifier = Modifier.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
if (localChatRoom.participants.size == 1) {
Text(
text = "Note to Self (${localChatRoom.participants.first().profile?.humanReadableNameOrPubkey()})"
)
} else {
// Remove the active user publicKey from participants...
val participantNames = localChatRoom.participants.filter { it.participant.participantPublicKey != localChatRoom.chatRoom.userPublicKey }.map { it.profile?.humanReadableNameOrPubkey() ?: "unknown participant" }
Text(
text = localChatRoom.chatRoom.subject ?: participantNames.joinToString()
)
}
Text(
text = localChatMessage.chatMessage.senderPublicKey // TODO: Get send name...
)
Text(
text = localChatMessage.chatMessage.content
)
}
}
}

View File

@@ -1,10 +1,10 @@
package ac.cord.auxiliary.compose.ui.view.state
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatRoom
import ac.cord.auxiliary.compose.database.model.intermdiate.LocalChatMessage
sealed interface ChatRoomDetailMessageListUIState {
data class Loaded(
val chatRoomList: List<LocalChatRoom>
val chatMessageList: List<LocalChatMessage>
): ChatRoomDetailMessageListUIState
data object Error: ChatRoomDetailMessageListUIState