Implement action messages in messages history
This commit is contained in:
+45
-12
@@ -1,7 +1,6 @@
|
||||
package com.meloda.app.fast.messageshistory
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
@@ -14,14 +13,18 @@ import com.meloda.app.fast.common.UserConfig
|
||||
import com.meloda.app.fast.common.extensions.listenValue
|
||||
import com.meloda.app.fast.common.extensions.setValue
|
||||
import com.meloda.app.fast.common.extensions.updateValue
|
||||
import com.meloda.app.fast.common.provider.ResourceProvider
|
||||
import com.meloda.app.fast.data.LongPollUpdatesParser
|
||||
import com.meloda.app.fast.data.VkMemoryCache
|
||||
import com.meloda.app.fast.data.api.conversations.ConversationsUseCase
|
||||
import com.meloda.app.fast.data.api.messages.MessagesUseCase
|
||||
import com.meloda.app.fast.data.processState
|
||||
import com.meloda.app.fast.datastore.AppSettings
|
||||
import com.meloda.app.fast.datastore.SettingsKeys
|
||||
import com.meloda.app.fast.datastore.UserSettings
|
||||
import com.meloda.app.fast.messageshistory.model.ActionMode
|
||||
import com.meloda.app.fast.messageshistory.model.MessagesHistoryScreenState
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
import com.meloda.app.fast.messageshistory.navigation.MessagesHistory
|
||||
import com.meloda.app.fast.messageshistory.util.asPresentation
|
||||
import com.meloda.app.fast.messageshistory.util.extractAvatar
|
||||
@@ -62,7 +65,8 @@ class MessagesHistoryViewModelImpl(
|
||||
private val messagesUseCase: MessagesUseCase,
|
||||
private val conversationsUseCase: ConversationsUseCase,
|
||||
private val preferences: SharedPreferences,
|
||||
private val resources: Resources,
|
||||
private val resourceProvider: ResourceProvider,
|
||||
private val userSettings: UserSettings,
|
||||
updatesParser: LongPollUpdatesParser,
|
||||
savedStateHandle: SavedStateHandle
|
||||
) : MessagesHistoryViewModel, ViewModel() {
|
||||
@@ -92,6 +96,8 @@ class MessagesHistoryViewModelImpl(
|
||||
updatesParser.onMessageEdited(::handleEditedMessage)
|
||||
updatesParser.onMessageIncomingRead(::handleReadIncomingEvent)
|
||||
updatesParser.onMessageOutgoingRead(::handleReadOutgoingEvent)
|
||||
|
||||
userSettings.showTimeInActionMessages.listenValue(::toggleShowTimeInActionMessages)
|
||||
}
|
||||
|
||||
override fun onRefresh() {
|
||||
@@ -169,19 +175,23 @@ class MessagesHistoryViewModelImpl(
|
||||
}
|
||||
|
||||
val newMessage = message.asPresentation(
|
||||
resourceProvider = resourceProvider,
|
||||
showDate = false,
|
||||
showName = false,
|
||||
prevMessage = prevMessage,
|
||||
nextMessage = null
|
||||
nextMessage = null,
|
||||
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||
)
|
||||
newMessages.add(0, newMessage)
|
||||
|
||||
prevMessage?.let { prev ->
|
||||
newMessages[1] = prev.asPresentation(
|
||||
resourceProvider = resourceProvider,
|
||||
showDate = false,
|
||||
showName = false,
|
||||
prevMessage = prevMessage,
|
||||
nextMessage = messages.value.first()
|
||||
nextMessage = messages.value.first(),
|
||||
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||
)
|
||||
}
|
||||
|
||||
@@ -196,10 +206,12 @@ class MessagesHistoryViewModelImpl(
|
||||
.indexOfFirstOrNull { it.id == message.id }
|
||||
?.let { index ->
|
||||
val newMessage = message.asPresentation(
|
||||
resourceProvider = resourceProvider,
|
||||
showDate = false,
|
||||
showName = false,
|
||||
prevMessage = messages.value.getOrNull(index + 1),
|
||||
nextMessage = messages.value.getOrNull(index - 1)
|
||||
nextMessage = messages.value.getOrNull(index - 1),
|
||||
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||
)
|
||||
|
||||
val newMessages = screenState.value.messages.toMutableList()
|
||||
@@ -248,10 +260,12 @@ class MessagesHistoryViewModelImpl(
|
||||
|
||||
val loadedMessages = fullMessages.mapIndexed { index, message ->
|
||||
message.asPresentation(
|
||||
resourceProvider = resourceProvider,
|
||||
showDate = false,
|
||||
showName = false,
|
||||
prevMessage = messages.getOrNull(index + 1),
|
||||
nextMessage = messages.getOrNull(index - 1),
|
||||
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||
)
|
||||
}
|
||||
|
||||
@@ -268,11 +282,8 @@ class MessagesHistoryViewModelImpl(
|
||||
?.let { conversation ->
|
||||
newState = newState.copy(
|
||||
title = conversation.extractTitle(
|
||||
useContactName = preferences.getBoolean(
|
||||
SettingsKeys.KEY_USE_CONTACT_NAMES,
|
||||
SettingsKeys.DEFAULT_VALUE_USE_CONTACT_NAMES
|
||||
),
|
||||
resources = resources
|
||||
useContactName = AppSettings.General.useContactNames,
|
||||
resources = resourceProvider.resources
|
||||
),
|
||||
avatar = conversation.extractAvatar()
|
||||
)
|
||||
@@ -337,10 +348,12 @@ class MessagesHistoryViewModelImpl(
|
||||
|
||||
val newMessages = screenState.value.messages.toMutableList()
|
||||
val newUiMessage = newMessage.asPresentation(
|
||||
resourceProvider = resourceProvider,
|
||||
showDate = false,
|
||||
showName = false,
|
||||
prevMessage = messages.value.firstOrNull(),
|
||||
nextMessage = null
|
||||
nextMessage = null,
|
||||
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||
)
|
||||
newMessages.add(0, newUiMessage)
|
||||
|
||||
@@ -373,7 +386,9 @@ class MessagesHistoryViewModelImpl(
|
||||
val messages = screenState.value.messages.toMutableList()
|
||||
|
||||
messages.indexOfOrNull(newUiMessage)?.let { index ->
|
||||
messages[index] = messages[index].copy(id = messageId)
|
||||
(messages[index] as? UiItem.Message)?.let { message ->
|
||||
messages[index] = message.copy(id = messageId)
|
||||
}
|
||||
}
|
||||
|
||||
screenState.setValue { old -> old.copy(messages = messages) }
|
||||
@@ -490,6 +505,24 @@ class MessagesHistoryViewModelImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleShowTimeInActionMessages(show: Boolean) {
|
||||
val messages = messages.value
|
||||
val uiMessages = messages.mapIndexed { index, item ->
|
||||
item.asPresentation(
|
||||
resourceProvider = resourceProvider,
|
||||
showDate = false,
|
||||
showName = false,
|
||||
prevMessage = messages.getOrNull(index + 1),
|
||||
nextMessage = messages.getOrNull(index - 1),
|
||||
showTimeInActionMessages = show
|
||||
)
|
||||
}
|
||||
|
||||
screenState.setValue { old ->
|
||||
old.copy(messages = uiMessages)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MESSAGES_LOAD_COUNT = 30
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ data class MessagesHistoryScreenState(
|
||||
val title: String,
|
||||
val status: String?,
|
||||
val avatar: UiImage,
|
||||
val messages: List<UiMessage>,
|
||||
val messages: List<UiItem>,
|
||||
val message: String,
|
||||
val attachments: List<VkAttachment>,
|
||||
val isLoading: Boolean,
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.meloda.app.fast.messageshistory.model
|
||||
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import com.meloda.app.fast.common.model.UiImage
|
||||
|
||||
sealed class UiItem(
|
||||
open val id: Int,
|
||||
val cmId: Int
|
||||
) {
|
||||
|
||||
data class Message(
|
||||
override val id: Int,
|
||||
val conversationMessageId: Int,
|
||||
val text: String?,
|
||||
val isOut: Boolean,
|
||||
val fromId: Int,
|
||||
val date: String,
|
||||
val randomId: Int,
|
||||
val isInChat: Boolean,
|
||||
val name: String,
|
||||
val showDate: Boolean,
|
||||
val showAvatar: Boolean,
|
||||
val showName: Boolean,
|
||||
val avatar: UiImage,
|
||||
val isEdited: Boolean
|
||||
) : UiItem(id, conversationMessageId)
|
||||
|
||||
data class ActionMessage(
|
||||
override val id: Int,
|
||||
val conversationMessageId: Int,
|
||||
val text: AnnotatedString,
|
||||
val actionCmId: Int?
|
||||
) : UiItem(id, conversationMessageId)
|
||||
}
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.meloda.app.fast.messageshistory.model
|
||||
|
||||
import com.meloda.app.fast.common.model.UiImage
|
||||
|
||||
data class UiMessage(
|
||||
val id: Int,
|
||||
val conversationMessageId: Int,
|
||||
val text: String?,
|
||||
val isOut: Boolean,
|
||||
val fromId: Int,
|
||||
val date: String,
|
||||
val randomId: Int,
|
||||
val isInChat: Boolean,
|
||||
val name: String,
|
||||
val showDate: Boolean,
|
||||
val showAvatar: Boolean,
|
||||
val showName: Boolean,
|
||||
val avatar: UiImage,
|
||||
val isEdited: Boolean
|
||||
)
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.meloda.app.fast.messageshistory.presentation
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
|
||||
@Composable
|
||||
fun ActionMessageItem(
|
||||
item: UiItem.ActionMessage,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit = {}
|
||||
) {
|
||||
Text(
|
||||
text = item.text,
|
||||
modifier = modifier
|
||||
.padding(horizontal = 32.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.then(
|
||||
if (item.actionCmId != null) {
|
||||
Modifier.clickable(onClick = onClick)
|
||||
}
|
||||
else Modifier
|
||||
)
|
||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(5.dp))
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = 32.dp,
|
||||
vertical = 4.dp
|
||||
),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ActionMessageItemPreview() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(10.dp)
|
||||
) {
|
||||
ActionMessageItem(
|
||||
item = UiItem.ActionMessage(
|
||||
id = 0,
|
||||
text = buildAnnotatedString {
|
||||
append("You pinned message \"wow hello there\"")
|
||||
},
|
||||
actionCmId = null,
|
||||
conversationMessageId = 2135
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -25,12 +25,12 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.rememberAsyncImagePainter
|
||||
import coil.imageLoader
|
||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
|
||||
@Composable
|
||||
fun IncomingMessageBubble(
|
||||
modifier: Modifier = Modifier,
|
||||
message: UiMessage,
|
||||
message: UiItem.Message,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
|
||||
+13
-2
@@ -78,6 +78,8 @@ import com.meloda.app.fast.messageshistory.MessagesHistoryViewModel
|
||||
import com.meloda.app.fast.messageshistory.MessagesHistoryViewModelImpl
|
||||
import com.meloda.app.fast.messageshistory.model.ActionMode
|
||||
import com.meloda.app.fast.messageshistory.model.MessagesHistoryScreenState
|
||||
import com.meloda.app.fast.messageshistory.util.firstMessage
|
||||
import com.meloda.app.fast.messageshistory.util.indexOfMessageByCmId
|
||||
import com.meloda.app.fast.model.BaseError
|
||||
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||
import com.meloda.app.fast.ui.util.ImmutableList
|
||||
@@ -142,6 +144,8 @@ fun MessagesHistoryScreen(
|
||||
) {
|
||||
val view = LocalView.current
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val preferences: SharedPreferences = koinInject()
|
||||
val currentTheme = LocalThemeConfig.current
|
||||
|
||||
@@ -250,7 +254,7 @@ fun MessagesHistoryScreen(
|
||||
|
||||
onChatMaterialsDropdownItemClicked(
|
||||
screenState.conversationId,
|
||||
screenState.messages.first().conversationMessageId
|
||||
screenState.messages.firstMessage().conversationMessageId
|
||||
)
|
||||
},
|
||||
text = {
|
||||
@@ -313,7 +317,14 @@ fun MessagesHistoryScreen(
|
||||
immutableMessages = ImmutableList.copyOf(screenState.messages),
|
||||
isPaginating = screenState.isPaginating,
|
||||
enableAnimations = animationsEnabled,
|
||||
messageBarHeight = messageBarHeight
|
||||
messageBarHeight = messageBarHeight,
|
||||
onRequestScrollToCmId = { cmId ->
|
||||
coroutineScope.launch {
|
||||
listState.animateScrollToItem(
|
||||
index = screenState.messages.indexOfMessageByCmId(cmId)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Column(
|
||||
|
||||
+49
-27
@@ -17,7 +17,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||
import com.meloda.app.fast.ui.util.ImmutableList
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
@@ -31,10 +31,11 @@ fun MessagesList(
|
||||
modifier: Modifier = Modifier,
|
||||
hazeState: HazeState,
|
||||
listState: LazyListState,
|
||||
immutableMessages: ImmutableList<UiMessage>,
|
||||
immutableMessages: ImmutableList<UiItem>,
|
||||
isPaginating: Boolean,
|
||||
enableAnimations: Boolean,
|
||||
messageBarHeight: Dp
|
||||
messageBarHeight: Dp,
|
||||
onRequestScrollToCmId: (cmId: Int) -> Unit = {}
|
||||
) {
|
||||
val messages = immutableMessages.toList()
|
||||
val currentTheme = LocalThemeConfig.current
|
||||
@@ -65,32 +66,53 @@ fun MessagesList(
|
||||
|
||||
items(
|
||||
items = messages,
|
||||
key = UiMessage::id,
|
||||
) { message ->
|
||||
if (message.isOut) {
|
||||
OutgoingMessageBubble(
|
||||
modifier =
|
||||
Modifier.then(
|
||||
if (enableAnimations) Modifier.animateItem(
|
||||
fadeInSpec = null,
|
||||
fadeOutSpec = null
|
||||
key = UiItem::id,
|
||||
contentType = { item ->
|
||||
when (item) {
|
||||
is UiItem.ActionMessage -> "action_message"
|
||||
is UiItem.Message -> "message"
|
||||
}
|
||||
}
|
||||
) { item ->
|
||||
when (item) {
|
||||
is UiItem.ActionMessage -> {
|
||||
ActionMessageItem(
|
||||
item = item,
|
||||
onClick = {
|
||||
if (item.actionCmId != null) {
|
||||
onRequestScrollToCmId(item.actionCmId)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
is UiItem.Message -> {
|
||||
if (item.isOut) {
|
||||
OutgoingMessageBubble(
|
||||
modifier =
|
||||
Modifier.then(
|
||||
if (enableAnimations) Modifier.animateItem(
|
||||
fadeInSpec = null,
|
||||
fadeOutSpec = null
|
||||
)
|
||||
else Modifier
|
||||
),
|
||||
message = item,
|
||||
)
|
||||
else Modifier
|
||||
),
|
||||
message = message,
|
||||
)
|
||||
} else {
|
||||
IncomingMessageBubble(
|
||||
modifier =
|
||||
Modifier.then(
|
||||
if (enableAnimations) Modifier.animateItem(
|
||||
fadeInSpec = null,
|
||||
fadeOutSpec = null
|
||||
} else {
|
||||
IncomingMessageBubble(
|
||||
modifier =
|
||||
Modifier.then(
|
||||
if (enableAnimations) Modifier.animateItem(
|
||||
fadeInSpec = null,
|
||||
fadeOutSpec = null
|
||||
)
|
||||
else Modifier
|
||||
),
|
||||
message = item,
|
||||
)
|
||||
else Modifier
|
||||
),
|
||||
message = message,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
+2
-2
@@ -14,12 +14,12 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.meloda.app.fast.common.extensions.orDots
|
||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
|
||||
@Composable
|
||||
fun OutgoingMessageBubble(
|
||||
modifier: Modifier = Modifier,
|
||||
message: UiMessage,
|
||||
message: UiItem.Message,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.meloda.app.fast.messageshistory.util
|
||||
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
|
||||
fun List<UiItem>.firstMessage(): UiItem.Message = first() as UiItem.Message
|
||||
|
||||
fun List<UiItem>.indexOfMessageById(messageId: Int): Int =
|
||||
indexOfFirst { it.id == messageId }
|
||||
|
||||
fun List<UiItem>.findMessageById(messageId: Int): UiItem.Message =
|
||||
first { it.id == messageId } as UiItem.Message
|
||||
|
||||
fun List<UiItem>.indexOfMessageByCmId(cmId: Int): Int =
|
||||
indexOfFirst { it.cmId == cmId }
|
||||
|
||||
fun List<UiItem>.findMessageByCmId(cmId: Int): UiItem.Message =
|
||||
first { it.cmId == cmId } as UiItem.Message
|
||||
+438
-21
@@ -1,17 +1,22 @@
|
||||
package com.meloda.app.fast.messageshistory.util
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.meloda.app.fast.common.model.UiImage
|
||||
import com.meloda.app.fast.common.model.UiText
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import com.meloda.app.fast.common.UserConfig
|
||||
import com.meloda.app.fast.common.extensions.orDots
|
||||
import com.meloda.app.fast.common.model.UiImage
|
||||
import com.meloda.app.fast.common.model.UiText
|
||||
import com.meloda.app.fast.common.model.parseString
|
||||
import com.meloda.app.fast.common.provider.ResourceProvider
|
||||
import com.meloda.app.fast.data.VkMemoryCache
|
||||
import com.meloda.app.fast.ui.R
|
||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
||||
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||
import com.meloda.app.fast.model.api.PeerType
|
||||
import com.meloda.app.fast.model.api.domain.VkConversation
|
||||
import com.meloda.app.fast.model.api.domain.VkMessage
|
||||
import com.meloda.app.fast.ui.R
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import com.meloda.app.fast.ui.R as UiR
|
||||
@@ -85,26 +90,42 @@ fun VkConversation.extractTitle(
|
||||
}.parseString(resources).orDots()
|
||||
|
||||
fun VkMessage.asPresentation(
|
||||
resourceProvider: ResourceProvider,
|
||||
showDate: Boolean,
|
||||
showName: Boolean,
|
||||
prevMessage: VkMessage?,
|
||||
nextMessage: VkMessage?
|
||||
): UiMessage = UiMessage(
|
||||
id = id,
|
||||
conversationMessageId = conversationMessageId,
|
||||
text = text,
|
||||
isOut = isOut,
|
||||
fromId = fromId,
|
||||
date = extractDate(),
|
||||
randomId = randomId,
|
||||
isInChat = isPeerChat(),
|
||||
name = extractTitle(),
|
||||
showDate = showDate,
|
||||
showAvatar = extractShowAvatar(nextMessage),
|
||||
showName = showName && extractShowName(prevMessage),
|
||||
avatar = extractAvatar(),
|
||||
isEdited = updateTime != null
|
||||
)
|
||||
nextMessage: VkMessage?,
|
||||
showTimeInActionMessages: Boolean
|
||||
): UiItem = when {
|
||||
action != null -> UiItem.ActionMessage(
|
||||
id = id,
|
||||
conversationMessageId = conversationMessageId,
|
||||
text = extractActionText(
|
||||
resources = resourceProvider.resources,
|
||||
youPrefix = resourceProvider.getString(R.string.you_message_prefix),
|
||||
showTime = showTimeInActionMessages
|
||||
) ?: buildAnnotatedString { },
|
||||
actionCmId = actionConversationMessageId
|
||||
)
|
||||
|
||||
else -> UiItem.Message(
|
||||
id = id,
|
||||
conversationMessageId = conversationMessageId,
|
||||
text = text,
|
||||
isOut = isOut,
|
||||
fromId = fromId,
|
||||
date = extractDate(),
|
||||
randomId = randomId,
|
||||
isInChat = isPeerChat(),
|
||||
name = extractTitle(),
|
||||
showDate = showDate,
|
||||
showAvatar = extractShowAvatar(nextMessage),
|
||||
showName = showName && extractShowName(prevMessage),
|
||||
avatar = extractAvatar(),
|
||||
isEdited = updateTime != null
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun VkMessage.extractShowAvatar(nextMessage: VkMessage?): Boolean {
|
||||
if (isOut) return false
|
||||
@@ -115,3 +136,399 @@ fun VkMessage.extractShowName(prevMessage: VkMessage?): Boolean {
|
||||
if (isOut || !isPeerChat()) return false
|
||||
return prevMessage == null || prevMessage.fromId != fromId
|
||||
}
|
||||
|
||||
fun VkMessage.extractActionText(
|
||||
resources: Resources,
|
||||
youPrefix: String,
|
||||
showTime: Boolean
|
||||
): AnnotatedString? {
|
||||
val lastMessage = this
|
||||
|
||||
val action = lastMessage.action ?: return null
|
||||
|
||||
val formattedMessageDate =
|
||||
SimpleDateFormat("HH:mm", Locale.getDefault()).format(lastMessage.date * 1000L)
|
||||
|
||||
val fromId = lastMessage.fromId
|
||||
val text = lastMessage.actionText.orDots()
|
||||
val groupName = lastMessage.group?.name.orDots()
|
||||
val userName = lastMessage.user?.fullName.orDots()
|
||||
val actionGroupName = lastMessage.actionGroup?.name.orDots()
|
||||
val actionUserName = lastMessage.actionUser?.fullName.orDots()
|
||||
val memberId = lastMessage.actionMemberId
|
||||
val isMemberUser = (memberId ?: 0) > 0
|
||||
val isMemberGroup = (memberId ?: 0) < 0
|
||||
|
||||
val prefix = when {
|
||||
lastMessage.fromId == UserConfig.userId -> youPrefix
|
||||
lastMessage.isGroup() -> groupName
|
||||
lastMessage.isUser() -> userName
|
||||
else -> null
|
||||
}.orDots()
|
||||
|
||||
val memberPrefix = when {
|
||||
memberId == UserConfig.userId -> youPrefix
|
||||
isMemberUser -> actionUserName
|
||||
isMemberGroup -> actionGroupName
|
||||
else -> null
|
||||
}.orDots()
|
||||
|
||||
return buildAnnotatedString {
|
||||
when (action) {
|
||||
VkMessage.Action.CHAT_CREATE -> {
|
||||
val string = UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_created,
|
||||
listOf(prefix, text)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
|
||||
val textStartIndex = string.indexOf(text)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = textStartIndex,
|
||||
end = textStartIndex + text.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_TITLE_UPDATE -> {
|
||||
val string = UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_renamed,
|
||||
listOf(prefix, text)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
|
||||
val textStartIndex = string.indexOf(text)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = textStartIndex,
|
||||
end = textStartIndex + text.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_PHOTO_UPDATE -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_photo_update,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_PHOTO_REMOVE -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_photo_remove,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_KICK_USER -> {
|
||||
if (memberId == fromId) {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_left,
|
||||
listOf(memberPrefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = memberPrefix.length
|
||||
)
|
||||
} else {
|
||||
val postfix =
|
||||
if (memberId == UserConfig.userId) youPrefix.lowercase()
|
||||
else lastMessage.actionUser.toString()
|
||||
|
||||
val string = UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_kicked,
|
||||
listOf(prefix, postfix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
|
||||
val postfixStartIndex = string.indexOf(postfix)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = postfixStartIndex,
|
||||
end = postfixStartIndex + postfix.length
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_INVITE_USER -> {
|
||||
if (memberId == lastMessage.fromId) {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_returned,
|
||||
listOf(memberPrefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = memberPrefix.length
|
||||
)
|
||||
} else {
|
||||
val postfix =
|
||||
if (memberId == UserConfig.userId) youPrefix.lowercase()
|
||||
else lastMessage.actionUser.toString()
|
||||
|
||||
val string = UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_invited,
|
||||
listOf(memberPrefix, postfix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
val postfixStartIndex = string.indexOf(postfix)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = postfixStartIndex,
|
||||
end = postfixStartIndex + postfix.length
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_INVITE_USER_BY_LINK -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_joined_by_link,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_INVITE_USER_BY_CALL -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_joined_by_call,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_INVITE_USER_BY_CALL_LINK -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_user_joined_by_call_link,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_PIN_MESSAGE -> {
|
||||
// TODO: 16/07/2024, Danil Nikolaev: get pinned message by cmid
|
||||
// val messageText = lastMessage.text.orEmpty().trim()
|
||||
// val croppedMessage = messageText.take(40)
|
||||
// val hasMessageText = messageText.isNotEmpty()
|
||||
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_pin_message,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
// .let { text ->
|
||||
// if (hasMessageText) {
|
||||
// text.plus("«%s»".format(croppedMessage))
|
||||
// .plus(if (messageText.length > 40) "..." else "")
|
||||
// } else text
|
||||
// }
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
|
||||
// if (hasMessageText) {
|
||||
// val croppedIndex = fullText.indexOf(croppedMessage)
|
||||
//
|
||||
// addStyle(
|
||||
// style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
// start = croppedIndex - 1,
|
||||
// end = croppedIndex - 1 + croppedMessage.length + 1
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_UNPIN_MESSAGE -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_unpin_message,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_SCREENSHOT -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_screenshot,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
|
||||
VkMessage.Action.CHAT_STYLE_UPDATE -> {
|
||||
UiText.ResourceParams(
|
||||
UiR.string.message_action_chat_style_update,
|
||||
listOf(prefix)
|
||||
).parseString(resources)
|
||||
.orEmpty()
|
||||
.let { text ->
|
||||
if (showTime) {
|
||||
text.plus("\n")
|
||||
.plus(formattedMessageDate)
|
||||
} else text
|
||||
}.also(::append)
|
||||
|
||||
addStyle(
|
||||
style = SpanStyle(fontWeight = FontWeight.Medium),
|
||||
start = 0,
|
||||
end = prefix.length
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user