Нормальный чат

This commit is contained in:
Халимов Рустам
2026-04-15 01:30:48 +03:00
parent 487cb1b12b
commit dcb733ac01
9 changed files with 20 additions and 24 deletions

View File

@@ -71,7 +71,6 @@ fun ChatDetailScreen(
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
val voiceRecorder = remember { VoiceRecorder(context) }
var textInput by remember { mutableStateOf("") }
var isEmojiPickerVisible by remember { mutableStateOf(false) }
var isRecording by remember { mutableStateOf(false) }
var recordingOffset by remember { mutableFloatStateOf(0f) }
@@ -601,8 +600,8 @@ fun ChatDetailScreen(
}
BasicTextField(
value = textInput,
onValueChange = { textInput = it },
value = state.inputText,
onValueChange = { viewModel.onInputTextChanged(it) },
modifier = Modifier
.weight(1f)
.onFocusChanged {
@@ -611,23 +610,14 @@ fun ChatDetailScreen(
}
},
textStyle = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurface),
cursorBrush = androidx.compose.ui.graphics.SolidColor(MaterialTheme.colorScheme.primary),
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Send,
imeAction = ImeAction.Default,
capitalization = KeyboardCapitalization.Sentences
),
keyboardActions = KeyboardActions(
onSend = {
if (textInput.isNotBlank() || state.pendingAttachments.isNotEmpty()) {
viewModel.sendMessage(textInput, onFail = { failedText ->
textInput = failedText
})
textInput = ""
isEmojiPickerVisible = false
}
}
),
maxLines = 6,
decorationBox = { innerTextField ->
if (textInput.isEmpty()) {
if (state.inputText.isEmpty()) {
Text(
stringResource(R.string.message_placeholder),
style = MaterialTheme.typography.bodyLarge,
@@ -643,15 +633,12 @@ fun ChatDetailScreen(
Spacer(modifier = Modifier.width(8.dp))
// 3. Кнопка действия (в синем квадрате)
val showMic = textInput.isEmpty() && state.pendingAttachments.isEmpty()
val showMic = state.inputText.isEmpty() && state.pendingAttachments.isEmpty()
Surface(
onClick = {
if (!showMic) {
viewModel.sendMessage(textInput, onFail = { failedText ->
textInput = failedText
})
textInput = ""
viewModel.sendMessage()
isEmojiPickerVisible = false
}
},
@@ -747,7 +734,7 @@ fun ChatDetailScreen(
gifCategories = state.gifCategories,
isGifsLoading = state.isGifsLoading,
error = state.error,
onEmojiSelected = { textInput += it },
onEmojiSelected = { viewModel.onInputTextChanged(state.inputText + it) },
onGifSelected = { url ->
viewModel.sendGif(url)
isEmojiPickerVisible = false

View File

@@ -40,7 +40,8 @@ data class ChatDetailState(
val initialScrollIndex: Int? = null,
val pendingAttachments: List<File> = emptyList(),
val isUploading: Boolean = false,
val isCompressionEnabled: Boolean = true
val isCompressionEnabled: Boolean = true,
val inputText: String = ""
)
@HiltViewModel
@@ -277,11 +278,19 @@ class ChatDetailViewModel @Inject constructor(
}
}
fun sendMessage(text: String, onFail: (String) -> Unit = {}) {
fun onInputTextChanged(text: String) {
_state.update { it.copy(inputText = text) }
}
fun sendMessage(onFail: (String) -> Unit = {}) {
val chatId = currentChatId ?: return
val text = _state.value.inputText
val pending = _state.value.pendingAttachments
if (text.isBlank() && pending.isEmpty()) return
// Clear input immediately to avoid double clicks and ensure UI experience
_state.update { it.copy(inputText = "") }
val tempId = "temp_${System.currentTimeMillis()}"
val userId = getCurrentUserId()