refactor: extract message composer actions
This commit is contained in:
+21
@@ -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<List<VkMessage>>,
|
||||
private val dialog: MutableStateFlow<MessageDialog?>,
|
||||
private val selectedMessages: MutableStateFlow<List<VkMessage>>,
|
||||
private val uiMessages: MutableStateFlow<List<MessageUiItem>>,
|
||||
private val isNeedToScrollToIndex: MutableStateFlow<Int?>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+51
@@ -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
|
||||
|
||||
|
||||
+20
-84
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user