From 26b21b1361596313256d3510049920f3d2c72d4d Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Mon, 18 May 2026 16:34:14 +0200 Subject: [PATCH] Show chatroom list --- .../compose/database/model/ChatRoom.kt | 11 +- .../compose/ui/composable/HomeScreen.kt | 16 +- ...tViewModel.kt => ChatRoomListViewModel.kt} | 207 +++++++----------- .../ui/view/state/ChatRoomListUIState.kt | 13 ++ .../ui/view/state/DirectMessageListUIState.kt | 13 -- 5 files changed, 109 insertions(+), 151 deletions(-) rename composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/{DirectMessageListViewModel.kt => ChatRoomListViewModel.kt} (51%) create mode 100755 composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/ChatRoomListUIState.kt delete mode 100755 composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/DirectMessageListUIState.kt diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/ChatRoom.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/ChatRoom.kt index 31260af1..3dabf29c 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/ChatRoom.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/database/model/ChatRoom.kt @@ -8,6 +8,7 @@ import androidx.room3.Entity import androidx.room3.ForeignKey import androidx.room3.PrimaryKey import com.vitorpamplona.quartz.nip01Core.core.HexKey +import kotlin.time.Clock import kotlin.time.Instant @Entity( @@ -69,11 +70,11 @@ data class ChatRoom( // Might want to focus on the other last messages... val initialGiftWrapUnsignedId: String, - override val createdAt: Instant, - override val updatedAt: Instant, - override val savedAt: Instant, - override val viewedAt: Instant?, - override val deletedAt: Instant?, + override val createdAt: Instant = Clock.System.now(), + override val updatedAt: Instant = createdAt, + override val savedAt: Instant = createdAt, + override val viewedAt: Instant? = null, + override val deletedAt: Instant? = null, ): TimestampedEntity, LocalStoreEntity, UserViewableEntity, SoftDeletableEntity { } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/HomeScreen.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/HomeScreen.kt index 6e5265cb..34b15ae2 100644 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/composable/HomeScreen.kt @@ -12,10 +12,10 @@ import ac.cord.auxiliary.compose.ui.theme.AuxTheme import ac.cord.auxiliary.compose.ui.view.model.FeedListViewModel import ac.cord.auxiliary.compose.ui.view.model.HomeScreenType import ac.cord.auxiliary.compose.ui.view.model.HomeViewModel -import ac.cord.auxiliary.compose.ui.view.model.DirectMessageListViewModel +import ac.cord.auxiliary.compose.ui.view.model.ChatRoomListViewModel import ac.cord.auxiliary.compose.ui.view.state.FeedListUIState import ac.cord.auxiliary.compose.ui.view.state.HomeScreenUIState -import ac.cord.auxiliary.compose.ui.view.state.DirectMessageListUIState +import ac.cord.auxiliary.compose.ui.view.state.ChatRoomListUIState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -211,10 +211,10 @@ fun HomeScreen( } } HomeScreenType.Messages -> { - val directMessageListViewModel: DirectMessageListViewModel = viewModel( + val chatRoomListViewModel: ChatRoomListViewModel = viewModel( key = homeScreenTypeType.name, - factory = DirectMessageListViewModel.factory( - initialDirectMessageListUIState = DirectMessageListUIState.Loading, + factory = ChatRoomListViewModel.factory( + initialChatRoomListUIState = ChatRoomListUIState.Loading, publicKey = homeScreenUIState.profileWithFollowing.profile.publicKey, synchronizationFilter = homeScreenViewModel.getSynchronizationFilter( homeScreenTypeType, @@ -224,8 +224,8 @@ fun HomeScreen( ), ) - key(directMessageListViewModel.directMessageListUIState) { - directMessageListViewModel.RenderFeed( + key(true) { + chatRoomListViewModel.RenderFeed( onNavigateToDirectMessageDetail = { onNavigateToDirectMessageDetail.invoke() } @@ -233,7 +233,7 @@ fun HomeScreen( } key(true) { - directMessageListViewModel.initiate() + chatRoomListViewModel.initiate() } } } diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/DirectMessageListViewModel.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/ChatRoomListViewModel.kt similarity index 51% rename from composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/DirectMessageListViewModel.kt rename to composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/ChatRoomListViewModel.kt index af7137c3..70a81e87 100755 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/DirectMessageListViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/model/ChatRoomListViewModel.kt @@ -1,17 +1,20 @@ package ac.cord.auxiliary.compose.ui.view.model +import ac.cord.auxiliary.compose.database.model.ChatRoom import ac.cord.auxiliary.compose.database.model.NegentropySynchronizeRequest import ac.cord.auxiliary.compose.database.model.types.SynchronizationFilter import ac.cord.auxiliary.compose.nostr.Relays import ac.cord.auxiliary.compose.repository.NostrRepository -import ac.cord.auxiliary.compose.ui.composable.navigation.routes.Route -import ac.cord.auxiliary.compose.ui.view.state.DirectMessageListUIState +import ac.cord.auxiliary.compose.ui.view.state.ChatRoomListUIState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material3.Card import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.LoadingIndicator @@ -36,14 +39,14 @@ import kotlinx.coroutines.IO import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch -class DirectMessageListViewModel( - initialDirectMessageListUIState: DirectMessageListUIState, +class ChatRoomListViewModel( + initialChatRoomListUIState: ChatRoomListUIState, val publicKey: String, val synchronizationFilter: SynchronizationFilter, val nostrRepository: NostrRepository ): ViewModel() { val logger = Logger.withTag(TAG) - var directMessageListUIState: DirectMessageListUIState by mutableStateOf(initialDirectMessageListUIState) + var chatRoomListUIState: ChatRoomListUIState by mutableStateOf(initialChatRoomListUIState) private set val isSynchronizationPending: MutableState = mutableStateOf(false) @@ -59,9 +62,38 @@ class DirectMessageListViewModel( viewModelScope.launch(Dispatchers.IO) { nostrRepository.observeProfileWithFollowing( publicKey - ).collect { - directMessageListUIState = DirectMessageListUIState.Loaded( - directMessageList = emptyList() + ).distinctUntilChanged().collect { + chatRoomListUIState = ChatRoomListUIState.Loaded( + chatRoomList = listOf( + ChatRoom( + id ="steveBikoId", + userPublicKey = "steveBikoId", + name = "Steve Biko", + subject = "BC: Systems", + initialGiftWrapUnsignedId = "", + ), + ChatRoom( + id = "chrisHaniId", + userPublicKey = "chrisHaniId", + name = "Chris Hani", + subject = "MK: Gym", + initialGiftWrapUnsignedId = "", + ), + ChatRoom( + id = "desmondTutuId", + userPublicKey = "desmondTutuId", + name = "Desmond Tutu", + subject = "TRC: Masses", + initialGiftWrapUnsignedId = "", + ), + ChatRoom( + id = "hipHopPantsulaId", + userPublicKey = "hipHopPantsulaId", + name = "Hip Hop Pantsula", + subject = "Motswako: Jabba", + initialGiftWrapUnsignedId = "", + ) + ) ) } } @@ -107,8 +139,8 @@ class DirectMessageListViewModel( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - when (val directMessageListUIState = directMessageListUIState) { - DirectMessageListUIState.Error -> { + when (val chatRoomListUIState = chatRoomListUIState) { + ChatRoomListUIState.Error -> { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally @@ -121,131 +153,56 @@ class DirectMessageListViewModel( ) } } - is DirectMessageListUIState.Loaded -> { + is ChatRoomListUIState.Loaded -> { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(10.dp) ) { - Text( - text = "Messages" - ) - Card( - modifier = Modifier.fillMaxWidth(), - onClick = { - onNavigateToDirectMessageDetail.invoke("") - } - ) { - Column( - modifier = Modifier.padding(20.dp), - horizontalAlignment = Alignment.CenterHorizontally, + if (chatRoomListUIState.chatRoomList.isEmpty()) { + Text( + text = "No messages. Go to a profile and send them a message." + ) + } else { + LazyColumn( + modifier = Modifier.fillMaxWidth(), + contentPadding = PaddingValues(10.dp), ) { - Text( - text = "Steve Biko" - ) - } + item { + Text( + text = "Messages" + ) + } + items( + items = chatRoomListUIState.chatRoomList, + key = { it.id } + ) { chatRoom -> + Card( + modifier = Modifier.fillMaxWidth(), + onClick = { + onNavigateToDirectMessageDetail.invoke("") + } + ) { + Column( + modifier = Modifier.padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = chatRoom.name ?: chatRoom.subject ?: "Unnamed chat" + ) + } + + } + } + } } - Card( - modifier = Modifier.fillMaxWidth(), - onClick = { - onNavigateToDirectMessageDetail.invoke("") - } - ) { - Column( - modifier = Modifier.padding(20.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "Chris Hani" - ) - } - } - - Card( - modifier = Modifier.fillMaxWidth(), - onClick = { - onNavigateToDirectMessageDetail.invoke("") - } - ) { - Column( - modifier = Modifier.padding(20.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "Desmond Tutu" - ) - } - - } - - Card( - modifier = Modifier.fillMaxWidth(), - onClick = { - onNavigateToDirectMessageDetail.invoke("") - } - ) { - Column( - modifier = Modifier.padding(20.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "Hip Hop Pantsula" - ) - } - - } - - Card( - modifier = Modifier.fillMaxWidth(), - onClick = { - onNavigateToDirectMessageDetail.invoke("") - } - ) { - Column( - modifier = Modifier.padding(20.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "Knee Cap" - ) - } - } } -// if (feedListUIState.messageList.isEmpty()) { -// Column( -// modifier = Modifier.fillMaxWidth(), -// horizontalAlignment = Alignment.CenterHorizontally -// ) { -// Spacer( -// modifier = Modifier.height(50.dp) -// ) -// Text( -// text = "No events were found", -// ) -// } -// } else { -// LazyColumn( -// modifier = Modifier.fillMaxWidth(), -// horizontalAlignment = Alignment.CenterHorizontally, -// verticalArrangement = Arrangement.spacedBy(10.dp) -// ) { -// items( -// items = feedListUIState.messageList, -// key = { profile -> profile.publicKey } -// ) { profile -> -// profile.RenderAsListItem( -// onNavigateToEvent = onNavigateToEvent -// ) -// } -// } -// } - } - DirectMessageListUIState.Loading -> { + ChatRoomListUIState.Loading -> { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally @@ -272,14 +229,14 @@ class DirectMessageListViewModel( const val TAG = "MessageListViewModel" fun factory( - initialDirectMessageListUIState: DirectMessageListUIState = DirectMessageListUIState.Loading, + initialChatRoomListUIState: ChatRoomListUIState = ChatRoomListUIState.Loading, publicKey: String, synchronizationFilter: SynchronizationFilter, nostrRepository: NostrRepository, ): ViewModelProvider.Factory = viewModelFactory { initializer { - DirectMessageListViewModel( - initialDirectMessageListUIState = initialDirectMessageListUIState, + ChatRoomListViewModel( + initialChatRoomListUIState = initialChatRoomListUIState, publicKey = publicKey, synchronizationFilter = synchronizationFilter, nostrRepository = nostrRepository diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/ChatRoomListUIState.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/ChatRoomListUIState.kt new file mode 100755 index 00000000..4c1bfda3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/ChatRoomListUIState.kt @@ -0,0 +1,13 @@ +package ac.cord.auxiliary.compose.ui.view.state + +import ac.cord.auxiliary.compose.database.model.ChatRoom + +sealed interface ChatRoomListUIState { + data class Loaded( + val chatRoomList: List + ): ChatRoomListUIState + + data object Error: ChatRoomListUIState + data object Loading: ChatRoomListUIState +} + diff --git a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/DirectMessageListUIState.kt b/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/DirectMessageListUIState.kt deleted file mode 100755 index bcfbd035..00000000 --- a/composeApp/src/commonMain/kotlin/ac/cord/auxiliary/compose/ui/view/state/DirectMessageListUIState.kt +++ /dev/null @@ -1,13 +0,0 @@ -package ac.cord.auxiliary.compose.ui.view.state - -import ac.cord.auxiliary.compose.database.model.Profile - -sealed interface DirectMessageListUIState { - data class Loaded( - val directMessageList: List - ): DirectMessageListUIState - - data object Error: DirectMessageListUIState - data object Loading: DirectMessageListUIState -} -