diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryInteractionHandler.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryInteractionHandler.kt index 83a7270b..8ac94544 100644 --- a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryInteractionHandler.kt +++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryInteractionHandler.kt @@ -1,12 +1,14 @@ package dev.meloda.fast.messageshistory import android.os.Bundle +import com.conena.nanokt.collections.indexOfFirstOrNull import dev.meloda.fast.common.extensions.getParcelableCompat import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.messageshistory.model.MessageDialog import dev.meloda.fast.messageshistory.model.MessageOption import dev.meloda.fast.messageshistory.model.MessagesHistoryScreenState import dev.meloda.fast.model.api.domain.VkMessage +import dev.meloda.fast.ui.model.vk.MessageUiItem import kotlinx.coroutines.flow.MutableStateFlow internal class MessagesHistoryInteractionHandler( @@ -14,6 +16,8 @@ internal class MessagesHistoryInteractionHandler( private val messages: MutableStateFlow>, private val dialog: MutableStateFlow, private val selectedMessages: MutableStateFlow>, + private val uiMessages: MutableStateFlow>, + private val isNeedToScrollToIndex: MutableStateFlow, private val messageActions: MessagesHistoryMessageActions, private val messageTransportActions: MessagesHistoryMessageTransportActions, private val syncUiMessages: () -> Unit @@ -243,4 +247,21 @@ internal class MessagesHistoryInteractionHandler( MessageDialog.MessagesDelete(selectedMessages.value) } } + + fun onPinnedMessageClicked(messageId: Long) { + val messageIndex = uiMessages.value.indexOfFirstOrNull { + it is MessageUiItem.Message && it.id == messageId + } + + if (messageIndex != null) { + isNeedToScrollToIndex.setValue { messageIndex } + } + } + + fun onUnpinMessageClicked() { + val pinnedMessageId = screenState.value.pinnedMessage?.id ?: return + dialog.setValue { + MessageDialog.MessageUnpin(pinnedMessageId) + } + } } diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryMessageActions.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryMessageActions.kt index 8030e0dc..6eb62c19 100644 --- a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryMessageActions.kt +++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryMessageActions.kt @@ -16,6 +16,7 @@ import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.provider.ResourceProvider import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.VkMemoryCache +import dev.meloda.fast.datastore.AppSettings import dev.meloda.fast.domain.MessagesUseCase import dev.meloda.fast.domain.util.extractReplySummary import dev.meloda.fast.domain.util.extractReplyTitle @@ -64,6 +65,38 @@ internal class MessagesHistoryMessageActions( } } + fun onMessageInputChanged(newText: TextFieldValue) { + screenState.setValue { old -> + old.copy( + message = newText, + actionMode = + when { + screenState.value.editCmId != null -> { + // TODO: 13/03/2026, Danil Nikolaev: also check if attachments is empty + if (newText.text.trim().isEmpty()) { + ActionMode.DELETE + } else { + ActionMode.EDIT + } + } + + newText.text.trim().isEmpty() -> ActionMode.RECORD_AUDIO + else -> ActionMode.SEND + } + ) + } + updateStyles() + } + + fun onEmojiButtonLongClicked() { + AppSettings.Features.fastText.takeIf { it.isNotBlank() }?.let { text -> + val newText = "${screenState.value.message.text}$text" + onMessageInputChanged( + TextFieldValue(text = newText, selection = TextRange(newText.length)) + ) + } + } + fun editMessage(cmId: Long) { screenState.setValue { old -> old.copy(editCmId = cmId) } @@ -118,6 +151,20 @@ internal class MessagesHistoryMessageActions( updateStyles() } + fun onActionButtonClicked() { + when (screenState.value.actionMode) { + ActionMode.DELETE -> confirmDeleteCurrentEditMessage() + ActionMode.EDIT -> editCurrentEditMessage() + ActionMode.RECORD_AUDIO -> { + screenState.setValue { it.copy(actionMode = ActionMode.RECORD_VIDEO) } + } + ActionMode.RECORD_VIDEO -> { + screenState.setValue { it.copy(actionMode = ActionMode.RECORD_AUDIO) } + } + ActionMode.SEND -> sendMessage() + } + } + fun onReplyCloseClicked() { replyToCmId = null screenState.setValue { old -> @@ -128,6 +175,10 @@ internal class MessagesHistoryMessageActions( } } + fun onKeyboardShown() { + showKeyboard.setValue { false } + } + fun sendMessage() { lastMessageText = screenState.value.message.text diff --git a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModelImpl.kt b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModelImpl.kt index e55bff3f..ed23db51 100644 --- a/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModelImpl.kt +++ b/feature/messageshistory/src/main/kotlin/dev/meloda/fast/messageshistory/MessagesHistoryViewModelImpl.kt @@ -2,22 +2,18 @@ package dev.meloda.fast.messageshistory import android.content.Context import android.os.Bundle -import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.TextFieldValue import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.conena.nanokt.collections.indexOfFirstOrNull import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.provider.ResourceProvider import dev.meloda.fast.data.processState -import dev.meloda.fast.datastore.AppSettings import dev.meloda.fast.domain.ConvoUseCase import dev.meloda.fast.domain.GetMessageReadPeersUseCase import dev.meloda.fast.domain.LongPollUpdatesReducer import dev.meloda.fast.domain.MessagesUseCase -import dev.meloda.fast.messageshistory.model.ActionMode import dev.meloda.fast.messageshistory.model.MessageDialog import dev.meloda.fast.messageshistory.model.MessageNavigation import dev.meloda.fast.messageshistory.model.MessagesHistoryScreenState @@ -119,6 +115,8 @@ class MessagesHistoryViewModelImpl( messages = messages, dialog = dialog, selectedMessages = selectedMessages, + uiMessages = uiMessages, + isNeedToScrollToIndex = isNeedToScrollToIndex, messageActions = messageActions, messageTransportActions = messageTransportActions, syncUiMessages = ::syncUiMessages @@ -182,55 +180,14 @@ class MessagesHistoryViewModelImpl( } - override fun onMessageInputChanged(newText: TextFieldValue) { - screenState.setValue { old -> - old.copy( - message = newText, - actionMode = - when { - screenState.value.editCmId != null -> { - // TODO: 13/03/2026, Danil Nikolaev: also check if attachments is empty - if (newText.text.trim().isEmpty()) { - ActionMode.DELETE - } else { - ActionMode.EDIT - } - } + override fun onMessageInputChanged(newText: TextFieldValue) = + messageActions.onMessageInputChanged(newText) - newText.text.trim().isEmpty() -> ActionMode.RECORD_AUDIO - else -> ActionMode.SEND - } - ) - } - updateStyles() - } + override fun onEmojiButtonLongClicked() = + messageActions.onEmojiButtonLongClicked() - override fun onEmojiButtonLongClicked() { - AppSettings.Features.fastText.takeIf { it.isNotBlank() }?.let { text -> - val newText = "${screenState.value.message.text}$text" - onMessageInputChanged( - TextFieldValue(text = newText, selection = TextRange(newText.length)) - ) - } - } - - override fun onActionButtonClicked() { - when (screenState.value.actionMode) { - ActionMode.DELETE -> messageActions.confirmDeleteCurrentEditMessage() - - ActionMode.EDIT -> messageActions.editCurrentEditMessage() - - ActionMode.RECORD_AUDIO -> { - screenState.setValue { it.copy(actionMode = ActionMode.RECORD_VIDEO) } - } - - ActionMode.RECORD_VIDEO -> { - screenState.setValue { it.copy(actionMode = ActionMode.RECORD_AUDIO) } - } - - ActionMode.SEND -> messageActions.sendMessage() - } - } + override fun onActionButtonClicked() = + messageActions.onActionButtonClicked() override fun onPaginationConditionsMet() { currentOffset.update { messages.value.size } @@ -243,25 +200,11 @@ class MessagesHistoryViewModelImpl( override fun onMessageLongClicked(messageId: Long) = interactionHandler.onMessageLongClicked(messageId) - override fun onPinnedMessageClicked(messageId: Long) { - val uiMessages = uiMessages.value - val messageIndex = uiMessages.indexOfFirstOrNull { - it is MessageUiItem.Message && it.id == messageId - } + override fun onPinnedMessageClicked(messageId: Long) = + interactionHandler.onPinnedMessageClicked(messageId) - if (messageIndex == null) { // сообщения нет в списке - // pizdets - } else { - isNeedToScrollToIndex.setValue { messageIndex } - } - } - - override fun onUnpinMessageClicked() { - val pinnedMessageId = screenState.value.pinnedMessage?.id ?: return - dialog.setValue { - MessageDialog.MessageUnpin(pinnedMessageId) - } - } + override fun onUnpinMessageClicked() = + interactionHandler.onUnpinMessageClicked() override fun onEditSelectedMessageClicked() = interactionHandler.onEditSelectedMessageClicked() @@ -269,37 +212,30 @@ class MessagesHistoryViewModelImpl( override fun onDeleteSelectedMessagesClicked() = interactionHandler.onDeleteSelectedMessagesClicked() - override fun onBoldClicked() { + override fun onBoldClicked() = messageActions.onBoldClicked() - } - override fun onItalicClicked() { + override fun onItalicClicked() = messageActions.onItalicClicked() - } - override fun onUnderlineClicked() { + override fun onUnderlineClicked() = messageActions.onUnderlineClicked() - } override fun onLinkClicked() { } - override fun onRegularClicked() { + override fun onRegularClicked() = messageActions.onRegularClicked() - } - override fun onReplyCloseClicked() { + override fun onReplyCloseClicked() = messageActions.onReplyCloseClicked() - } - override fun onRequestReplyToMessage(cmId: Long) { + override fun onRequestReplyToMessage(cmId: Long) = messageActions.replyToMessage(cmId) - } - override fun onKeyboardShown() { - showKeyboard.setValue { false } - } + override fun onKeyboardShown() = + messageActions.onKeyboardShown() override suspend fun loadMessageReadPeers(peerId: Long, cmId: Long): Int = suspendCancellableCoroutine {