Чат
This commit is contained in:
@@ -20,6 +20,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chats.presentation.components.EmojiPicker
|
||||
import chats.presentation.components.MessageBubble
|
||||
import core.presentation.components.AppAvatar
|
||||
import core.utils.VoiceRecorder
|
||||
import core.utils.copyUriToFile
|
||||
import java.io.File
|
||||
@@ -67,14 +68,22 @@ fun ChatDetailScreen(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Column {
|
||||
Text(chatName, style = MaterialTheme.typography.titleMedium)
|
||||
if (state.isTyping) {
|
||||
Text(
|
||||
stringResource(R.string.typing),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
AppAvatar(
|
||||
url = state.chatAvatar,
|
||||
name = state.chatName ?: chatName,
|
||||
size = 36.dp,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
Column {
|
||||
Text(state.chatName ?: chatName, style = MaterialTheme.typography.titleMedium)
|
||||
if (state.isTyping) {
|
||||
Text(
|
||||
stringResource(R.string.typing),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -116,9 +125,12 @@ fun ChatDetailScreen(
|
||||
items(state.messages) { message ->
|
||||
MessageBubble(
|
||||
message = message,
|
||||
isCurrentUser = message.senderId == viewModel.getCurrentUserId()
|
||||
isCurrentUser = message.senderId == viewModel.getCurrentUserId(),
|
||||
senderAvatar = if (message.senderId == viewModel.getCurrentUserId()) null else message.senderAvatar,
|
||||
onReactionClick = { emoji -> viewModel.addReaction(message.id, emoji) }
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (state.isLoading) {
|
||||
|
||||
@@ -19,6 +19,8 @@ import javax.inject.Inject
|
||||
|
||||
data class ChatDetailState(
|
||||
val messages: List<Message> = emptyList(),
|
||||
val chatName: String? = null,
|
||||
val chatAvatar: String? = null,
|
||||
val isLoading: Boolean = false,
|
||||
val isTyping: Boolean = false,
|
||||
val typingUser: String? = null,
|
||||
@@ -56,10 +58,25 @@ class ChatDetailViewModel @Inject constructor(
|
||||
|
||||
fun setChatId(chatId: String) {
|
||||
currentChatId = chatId
|
||||
loadChatInfo(chatId)
|
||||
loadMessages(chatId)
|
||||
observeSignalREvents()
|
||||
}
|
||||
|
||||
private fun loadChatInfo(chatId: String) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val chats = repository.getChats()
|
||||
val chat = chats.find { it.id == chatId }
|
||||
chat?.let { c ->
|
||||
_state.update { it.copy(chatName = c.name, chatAvatar = c.avatar) }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// Ignore info load error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMessages(chatId: String) {
|
||||
viewModelScope.launch {
|
||||
_state.update { it.copy(isLoading = true) }
|
||||
@@ -88,8 +105,9 @@ class ChatDetailViewModel @Inject constructor(
|
||||
when (event) {
|
||||
is ChatEvent.NewMessage -> {
|
||||
// Avoid adding duplicates if already loaded
|
||||
val baseUrl = serverConfig.getBaseUrl().removeSuffix("/api/")
|
||||
_state.update { s ->
|
||||
val domainMsg = event.message.toDomain()
|
||||
val domainMsg = event.message.toDomain(baseUrl)
|
||||
if (s.messages.none { it.id == domainMsg.id }) {
|
||||
s.copy(messages = s.messages + domainMsg)
|
||||
} else s
|
||||
|
||||
Reference in New Issue
Block a user