forked from melod1n/fast-messenger
Implement action messages in messages history
This commit is contained in:
@@ -4,10 +4,12 @@ import android.content.res.Resources
|
|||||||
|
|
||||||
interface ResourceProvider {
|
interface ResourceProvider {
|
||||||
|
|
||||||
|
val resources: Resources
|
||||||
|
|
||||||
fun getString(resId: Int): String
|
fun getString(resId: Int): String
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResourceProviderImpl(private val resources: Resources) : ResourceProvider {
|
class ResourceProviderImpl(override val resources: Resources) : ResourceProvider {
|
||||||
|
|
||||||
override fun getString(resId: Int): String {
|
override fun getString(resId: Int): String {
|
||||||
return resources.getString(resId)
|
return resources.getString(resId)
|
||||||
|
|||||||
@@ -180,6 +180,13 @@ object AppSettings {
|
|||||||
)
|
)
|
||||||
set(value) = put(SettingsKeys.KEY_SHOW_EMOJI_BUTTON, value)
|
set(value) = put(SettingsKeys.KEY_SHOW_EMOJI_BUTTON, value)
|
||||||
|
|
||||||
|
var showTimeInActionMessages: Boolean
|
||||||
|
get() = get(
|
||||||
|
SettingsKeys.KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||||
|
SettingsKeys.DEFAULT_VALUE_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES
|
||||||
|
)
|
||||||
|
set(value) = put(SettingsKeys.KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES, value)
|
||||||
|
|
||||||
var showDebugCategory: Boolean
|
var showDebugCategory: Boolean
|
||||||
get() = get(
|
get() = get(
|
||||||
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY,
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ object SettingsKeys {
|
|||||||
const val DEFAULT_APPEARANCE_LANGUAGE = ""
|
const val DEFAULT_APPEARANCE_LANGUAGE = ""
|
||||||
const val KEY_APPEARANCE_USE_BLUR = "appearance_use_blur"
|
const val KEY_APPEARANCE_USE_BLUR = "appearance_use_blur"
|
||||||
const val DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR = false
|
const val DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR = false
|
||||||
|
const val KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES =
|
||||||
|
"appearance_show_time_in_action_messages"
|
||||||
|
const val DEFAULT_VALUE_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES = false
|
||||||
|
|
||||||
const val KEY_FEATURES_FAST_TEXT = "features_fast_text"
|
const val KEY_FEATURES_FAST_TEXT = "features_fast_text"
|
||||||
const val DEFAULT_VALUE_FEATURES_FAST_TEXT = "¯\\_(ツ)_/¯"
|
const val DEFAULT_VALUE_FEATURES_FAST_TEXT = "¯\\_(ツ)_/¯"
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ interface UserSettings {
|
|||||||
val longPollInBackground: StateFlow<Boolean>
|
val longPollInBackground: StateFlow<Boolean>
|
||||||
val useBlur: StateFlow<Boolean>
|
val useBlur: StateFlow<Boolean>
|
||||||
val showEmojiButton: StateFlow<Boolean>
|
val showEmojiButton: StateFlow<Boolean>
|
||||||
|
val showTimeInActionMessages: StateFlow<Boolean>
|
||||||
val showDebugCategory: StateFlow<Boolean>
|
val showDebugCategory: StateFlow<Boolean>
|
||||||
|
|
||||||
fun onUseContactNamesChanged(use: Boolean)
|
fun onUseContactNamesChanged(use: Boolean)
|
||||||
@@ -42,6 +43,7 @@ interface UserSettings {
|
|||||||
fun onLongPollInBackgroundChanged(inBackground: Boolean)
|
fun onLongPollInBackgroundChanged(inBackground: Boolean)
|
||||||
fun onUseBlurChanged(use: Boolean)
|
fun onUseBlurChanged(use: Boolean)
|
||||||
fun onShowEmojiButtonChanged(show: Boolean)
|
fun onShowEmojiButtonChanged(show: Boolean)
|
||||||
|
fun onShowTimeInActionMessagesChanged(show: Boolean)
|
||||||
fun onShowDebugCategoryChanged(show: Boolean)
|
fun onShowDebugCategoryChanged(show: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +66,8 @@ class UserSettingsImpl : UserSettings {
|
|||||||
override val longPollInBackground = MutableStateFlow(AppSettings.Debug.longPollInBackground)
|
override val longPollInBackground = MutableStateFlow(AppSettings.Debug.longPollInBackground)
|
||||||
override val useBlur = MutableStateFlow(AppSettings.Debug.useBlur)
|
override val useBlur = MutableStateFlow(AppSettings.Debug.useBlur)
|
||||||
override val showEmojiButton = MutableStateFlow(AppSettings.Debug.showEmojiButton)
|
override val showEmojiButton = MutableStateFlow(AppSettings.Debug.showEmojiButton)
|
||||||
|
override val showTimeInActionMessages =
|
||||||
|
MutableStateFlow(AppSettings.Debug.showTimeInActionMessages)
|
||||||
override val showDebugCategory = MutableStateFlow(AppSettings.Debug.showDebugCategory)
|
override val showDebugCategory = MutableStateFlow(AppSettings.Debug.showDebugCategory)
|
||||||
|
|
||||||
override fun onUseContactNamesChanged(use: Boolean) {
|
override fun onUseContactNamesChanged(use: Boolean) {
|
||||||
@@ -118,6 +122,10 @@ class UserSettingsImpl : UserSettings {
|
|||||||
showEmojiButton.value = show
|
showEmojiButton.value = show
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onShowTimeInActionMessagesChanged(show: Boolean) {
|
||||||
|
showTimeInActionMessages.value = show
|
||||||
|
}
|
||||||
|
|
||||||
override fun onShowDebugCategoryChanged(show: Boolean) {
|
override fun onShowDebugCategoryChanged(show: Boolean) {
|
||||||
showDebugCategory.value = show
|
showDebugCategory.value = show
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-12
@@ -1,7 +1,6 @@
|
|||||||
package com.meloda.app.fast.messageshistory
|
package com.meloda.app.fast.messageshistory
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Resources
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.lifecycle.SavedStateHandle
|
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.listenValue
|
||||||
import com.meloda.app.fast.common.extensions.setValue
|
import com.meloda.app.fast.common.extensions.setValue
|
||||||
import com.meloda.app.fast.common.extensions.updateValue
|
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.LongPollUpdatesParser
|
||||||
import com.meloda.app.fast.data.VkMemoryCache
|
import com.meloda.app.fast.data.VkMemoryCache
|
||||||
import com.meloda.app.fast.data.api.conversations.ConversationsUseCase
|
import com.meloda.app.fast.data.api.conversations.ConversationsUseCase
|
||||||
import com.meloda.app.fast.data.api.messages.MessagesUseCase
|
import com.meloda.app.fast.data.api.messages.MessagesUseCase
|
||||||
import com.meloda.app.fast.data.processState
|
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.SettingsKeys
|
||||||
|
import com.meloda.app.fast.datastore.UserSettings
|
||||||
import com.meloda.app.fast.messageshistory.model.ActionMode
|
import com.meloda.app.fast.messageshistory.model.ActionMode
|
||||||
import com.meloda.app.fast.messageshistory.model.MessagesHistoryScreenState
|
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.navigation.MessagesHistory
|
||||||
import com.meloda.app.fast.messageshistory.util.asPresentation
|
import com.meloda.app.fast.messageshistory.util.asPresentation
|
||||||
import com.meloda.app.fast.messageshistory.util.extractAvatar
|
import com.meloda.app.fast.messageshistory.util.extractAvatar
|
||||||
@@ -62,7 +65,8 @@ class MessagesHistoryViewModelImpl(
|
|||||||
private val messagesUseCase: MessagesUseCase,
|
private val messagesUseCase: MessagesUseCase,
|
||||||
private val conversationsUseCase: ConversationsUseCase,
|
private val conversationsUseCase: ConversationsUseCase,
|
||||||
private val preferences: SharedPreferences,
|
private val preferences: SharedPreferences,
|
||||||
private val resources: Resources,
|
private val resourceProvider: ResourceProvider,
|
||||||
|
private val userSettings: UserSettings,
|
||||||
updatesParser: LongPollUpdatesParser,
|
updatesParser: LongPollUpdatesParser,
|
||||||
savedStateHandle: SavedStateHandle
|
savedStateHandle: SavedStateHandle
|
||||||
) : MessagesHistoryViewModel, ViewModel() {
|
) : MessagesHistoryViewModel, ViewModel() {
|
||||||
@@ -92,6 +96,8 @@ class MessagesHistoryViewModelImpl(
|
|||||||
updatesParser.onMessageEdited(::handleEditedMessage)
|
updatesParser.onMessageEdited(::handleEditedMessage)
|
||||||
updatesParser.onMessageIncomingRead(::handleReadIncomingEvent)
|
updatesParser.onMessageIncomingRead(::handleReadIncomingEvent)
|
||||||
updatesParser.onMessageOutgoingRead(::handleReadOutgoingEvent)
|
updatesParser.onMessageOutgoingRead(::handleReadOutgoingEvent)
|
||||||
|
|
||||||
|
userSettings.showTimeInActionMessages.listenValue(::toggleShowTimeInActionMessages)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRefresh() {
|
override fun onRefresh() {
|
||||||
@@ -169,19 +175,23 @@ class MessagesHistoryViewModelImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val newMessage = message.asPresentation(
|
val newMessage = message.asPresentation(
|
||||||
|
resourceProvider = resourceProvider,
|
||||||
showDate = false,
|
showDate = false,
|
||||||
showName = false,
|
showName = false,
|
||||||
prevMessage = prevMessage,
|
prevMessage = prevMessage,
|
||||||
nextMessage = null
|
nextMessage = null,
|
||||||
|
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||||
)
|
)
|
||||||
newMessages.add(0, newMessage)
|
newMessages.add(0, newMessage)
|
||||||
|
|
||||||
prevMessage?.let { prev ->
|
prevMessage?.let { prev ->
|
||||||
newMessages[1] = prev.asPresentation(
|
newMessages[1] = prev.asPresentation(
|
||||||
|
resourceProvider = resourceProvider,
|
||||||
showDate = false,
|
showDate = false,
|
||||||
showName = false,
|
showName = false,
|
||||||
prevMessage = prevMessage,
|
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 }
|
.indexOfFirstOrNull { it.id == message.id }
|
||||||
?.let { index ->
|
?.let { index ->
|
||||||
val newMessage = message.asPresentation(
|
val newMessage = message.asPresentation(
|
||||||
|
resourceProvider = resourceProvider,
|
||||||
showDate = false,
|
showDate = false,
|
||||||
showName = false,
|
showName = false,
|
||||||
prevMessage = messages.value.getOrNull(index + 1),
|
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()
|
val newMessages = screenState.value.messages.toMutableList()
|
||||||
@@ -248,10 +260,12 @@ class MessagesHistoryViewModelImpl(
|
|||||||
|
|
||||||
val loadedMessages = fullMessages.mapIndexed { index, message ->
|
val loadedMessages = fullMessages.mapIndexed { index, message ->
|
||||||
message.asPresentation(
|
message.asPresentation(
|
||||||
|
resourceProvider = resourceProvider,
|
||||||
showDate = false,
|
showDate = false,
|
||||||
showName = false,
|
showName = false,
|
||||||
prevMessage = messages.getOrNull(index + 1),
|
prevMessage = messages.getOrNull(index + 1),
|
||||||
nextMessage = messages.getOrNull(index - 1),
|
nextMessage = messages.getOrNull(index - 1),
|
||||||
|
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,11 +282,8 @@ class MessagesHistoryViewModelImpl(
|
|||||||
?.let { conversation ->
|
?.let { conversation ->
|
||||||
newState = newState.copy(
|
newState = newState.copy(
|
||||||
title = conversation.extractTitle(
|
title = conversation.extractTitle(
|
||||||
useContactName = preferences.getBoolean(
|
useContactName = AppSettings.General.useContactNames,
|
||||||
SettingsKeys.KEY_USE_CONTACT_NAMES,
|
resources = resourceProvider.resources
|
||||||
SettingsKeys.DEFAULT_VALUE_USE_CONTACT_NAMES
|
|
||||||
),
|
|
||||||
resources = resources
|
|
||||||
),
|
),
|
||||||
avatar = conversation.extractAvatar()
|
avatar = conversation.extractAvatar()
|
||||||
)
|
)
|
||||||
@@ -337,10 +348,12 @@ class MessagesHistoryViewModelImpl(
|
|||||||
|
|
||||||
val newMessages = screenState.value.messages.toMutableList()
|
val newMessages = screenState.value.messages.toMutableList()
|
||||||
val newUiMessage = newMessage.asPresentation(
|
val newUiMessage = newMessage.asPresentation(
|
||||||
|
resourceProvider = resourceProvider,
|
||||||
showDate = false,
|
showDate = false,
|
||||||
showName = false,
|
showName = false,
|
||||||
prevMessage = messages.value.firstOrNull(),
|
prevMessage = messages.value.firstOrNull(),
|
||||||
nextMessage = null
|
nextMessage = null,
|
||||||
|
showTimeInActionMessages = userSettings.showTimeInActionMessages.value
|
||||||
)
|
)
|
||||||
newMessages.add(0, newUiMessage)
|
newMessages.add(0, newUiMessage)
|
||||||
|
|
||||||
@@ -373,7 +386,9 @@ class MessagesHistoryViewModelImpl(
|
|||||||
val messages = screenState.value.messages.toMutableList()
|
val messages = screenState.value.messages.toMutableList()
|
||||||
|
|
||||||
messages.indexOfOrNull(newUiMessage)?.let { index ->
|
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) }
|
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 {
|
companion object {
|
||||||
const val MESSAGES_LOAD_COUNT = 30
|
const val MESSAGES_LOAD_COUNT = 30
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ data class MessagesHistoryScreenState(
|
|||||||
val title: String,
|
val title: String,
|
||||||
val status: String?,
|
val status: String?,
|
||||||
val avatar: UiImage,
|
val avatar: UiImage,
|
||||||
val messages: List<UiMessage>,
|
val messages: List<UiItem>,
|
||||||
val message: String,
|
val message: String,
|
||||||
val attachments: List<VkAttachment>,
|
val attachments: List<VkAttachment>,
|
||||||
val isLoading: Boolean,
|
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 androidx.compose.ui.unit.dp
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IncomingMessageBubble(
|
fun IncomingMessageBubble(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
message: UiMessage,
|
message: UiItem.Message,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
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.MessagesHistoryViewModelImpl
|
||||||
import com.meloda.app.fast.messageshistory.model.ActionMode
|
import com.meloda.app.fast.messageshistory.model.ActionMode
|
||||||
import com.meloda.app.fast.messageshistory.model.MessagesHistoryScreenState
|
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.model.BaseError
|
||||||
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
import com.meloda.app.fast.ui.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
@@ -142,6 +144,8 @@ fun MessagesHistoryScreen(
|
|||||||
) {
|
) {
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
val preferences: SharedPreferences = koinInject()
|
val preferences: SharedPreferences = koinInject()
|
||||||
val currentTheme = LocalThemeConfig.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
|
|
||||||
@@ -250,7 +254,7 @@ fun MessagesHistoryScreen(
|
|||||||
|
|
||||||
onChatMaterialsDropdownItemClicked(
|
onChatMaterialsDropdownItemClicked(
|
||||||
screenState.conversationId,
|
screenState.conversationId,
|
||||||
screenState.messages.first().conversationMessageId
|
screenState.messages.firstMessage().conversationMessageId
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
@@ -313,7 +317,14 @@ fun MessagesHistoryScreen(
|
|||||||
immutableMessages = ImmutableList.copyOf(screenState.messages),
|
immutableMessages = ImmutableList.copyOf(screenState.messages),
|
||||||
isPaginating = screenState.isPaginating,
|
isPaginating = screenState.isPaginating,
|
||||||
enableAnimations = animationsEnabled,
|
enableAnimations = animationsEnabled,
|
||||||
messageBarHeight = messageBarHeight
|
messageBarHeight = messageBarHeight,
|
||||||
|
onRequestScrollToCmId = { cmId ->
|
||||||
|
coroutineScope.launch {
|
||||||
|
listState.animateScrollToItem(
|
||||||
|
index = screenState.messages.indexOfMessageByCmId(cmId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
+30
-8
@@ -17,7 +17,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
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.theme.LocalThemeConfig
|
||||||
import com.meloda.app.fast.ui.util.ImmutableList
|
import com.meloda.app.fast.ui.util.ImmutableList
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
@@ -31,10 +31,11 @@ fun MessagesList(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
hazeState: HazeState,
|
hazeState: HazeState,
|
||||||
listState: LazyListState,
|
listState: LazyListState,
|
||||||
immutableMessages: ImmutableList<UiMessage>,
|
immutableMessages: ImmutableList<UiItem>,
|
||||||
isPaginating: Boolean,
|
isPaginating: Boolean,
|
||||||
enableAnimations: Boolean,
|
enableAnimations: Boolean,
|
||||||
messageBarHeight: Dp
|
messageBarHeight: Dp,
|
||||||
|
onRequestScrollToCmId: (cmId: Int) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val messages = immutableMessages.toList()
|
val messages = immutableMessages.toList()
|
||||||
val currentTheme = LocalThemeConfig.current
|
val currentTheme = LocalThemeConfig.current
|
||||||
@@ -65,9 +66,28 @@ fun MessagesList(
|
|||||||
|
|
||||||
items(
|
items(
|
||||||
items = messages,
|
items = messages,
|
||||||
key = UiMessage::id,
|
key = UiItem::id,
|
||||||
) { message ->
|
contentType = { item ->
|
||||||
if (message.isOut) {
|
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(
|
OutgoingMessageBubble(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.then(
|
Modifier.then(
|
||||||
@@ -77,7 +97,7 @@ fun MessagesList(
|
|||||||
)
|
)
|
||||||
else Modifier
|
else Modifier
|
||||||
),
|
),
|
||||||
message = message,
|
message = item,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
IncomingMessageBubble(
|
IncomingMessageBubble(
|
||||||
@@ -89,9 +109,11 @@ fun MessagesList(
|
|||||||
)
|
)
|
||||||
else Modifier
|
else Modifier
|
||||||
),
|
),
|
||||||
message = message,
|
message = item,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
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.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.meloda.app.fast.common.extensions.orDots
|
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
|
@Composable
|
||||||
fun OutgoingMessageBubble(
|
fun OutgoingMessageBubble(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
message: UiMessage,
|
message: UiItem.Message,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier.fillMaxWidth(),
|
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
|
||||||
+424
-7
@@ -1,17 +1,22 @@
|
|||||||
package com.meloda.app.fast.messageshistory.util
|
package com.meloda.app.fast.messageshistory.util
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.meloda.app.fast.common.model.UiImage
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import com.meloda.app.fast.common.model.UiText
|
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.UserConfig
|
||||||
import com.meloda.app.fast.common.extensions.orDots
|
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.model.parseString
|
||||||
|
import com.meloda.app.fast.common.provider.ResourceProvider
|
||||||
import com.meloda.app.fast.data.VkMemoryCache
|
import com.meloda.app.fast.data.VkMemoryCache
|
||||||
import com.meloda.app.fast.ui.R
|
import com.meloda.app.fast.messageshistory.model.UiItem
|
||||||
import com.meloda.app.fast.messageshistory.model.UiMessage
|
|
||||||
import com.meloda.app.fast.model.api.PeerType
|
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.VkConversation
|
||||||
import com.meloda.app.fast.model.api.domain.VkMessage
|
import com.meloda.app.fast.model.api.domain.VkMessage
|
||||||
|
import com.meloda.app.fast.ui.R
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import com.meloda.app.fast.ui.R as UiR
|
import com.meloda.app.fast.ui.R as UiR
|
||||||
@@ -85,11 +90,25 @@ fun VkConversation.extractTitle(
|
|||||||
}.parseString(resources).orDots()
|
}.parseString(resources).orDots()
|
||||||
|
|
||||||
fun VkMessage.asPresentation(
|
fun VkMessage.asPresentation(
|
||||||
|
resourceProvider: ResourceProvider,
|
||||||
showDate: Boolean,
|
showDate: Boolean,
|
||||||
showName: Boolean,
|
showName: Boolean,
|
||||||
prevMessage: VkMessage?,
|
prevMessage: VkMessage?,
|
||||||
nextMessage: VkMessage?
|
nextMessage: VkMessage?,
|
||||||
): UiMessage = UiMessage(
|
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,
|
id = id,
|
||||||
conversationMessageId = conversationMessageId,
|
conversationMessageId = conversationMessageId,
|
||||||
text = text,
|
text = text,
|
||||||
@@ -104,7 +123,9 @@ fun VkMessage.asPresentation(
|
|||||||
showName = showName && extractShowName(prevMessage),
|
showName = showName && extractShowName(prevMessage),
|
||||||
avatar = extractAvatar(),
|
avatar = extractAvatar(),
|
||||||
isEdited = updateTime != null
|
isEdited = updateTime != null
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun VkMessage.extractShowAvatar(nextMessage: VkMessage?): Boolean {
|
fun VkMessage.extractShowAvatar(nextMessage: VkMessage?): Boolean {
|
||||||
if (isOut) return false
|
if (isOut) return false
|
||||||
@@ -115,3 +136,399 @@ fun VkMessage.extractShowName(prevMessage: VkMessage?): Boolean {
|
|||||||
if (isOut || !isPeerChat()) return false
|
if (isOut || !isPeerChat()) return false
|
||||||
return prevMessage == null || prevMessage.fromId != fromId
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -230,6 +230,12 @@ class SettingsViewModelImpl(
|
|||||||
userSettings.onShowEmojiButtonChanged(show)
|
userSettings.onShowEmojiButtonChanged(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsKeys.KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES -> {
|
||||||
|
val show = newValue as? Boolean
|
||||||
|
?: SettingsKeys.DEFAULT_VALUE_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES
|
||||||
|
userSettings.onShowTimeInActionMessagesChanged(show)
|
||||||
|
}
|
||||||
|
|
||||||
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY -> {
|
SettingsKeys.KEY_SHOW_DEBUG_CATEGORY -> {
|
||||||
val show = newValue as? Boolean ?: false
|
val show = newValue as? Boolean ?: false
|
||||||
userSettings.onShowDebugCategoryChanged(show)
|
userSettings.onShowDebugCategoryChanged(show)
|
||||||
@@ -349,12 +355,6 @@ class SettingsViewModelImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val debugLongPollBackground = SettingsItem.Switch(
|
|
||||||
key = SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND,
|
|
||||||
defaultValue = SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND,
|
|
||||||
title = UiText.Resource(UiR.string.settings_features_long_poll_in_background_title),
|
|
||||||
text = UiText.Resource(UiR.string.settings_features_long_poll_in_background_summary)
|
|
||||||
)
|
|
||||||
|
|
||||||
val activityTitle = SettingsItem.Title(
|
val activityTitle = SettingsItem.Title(
|
||||||
key = "activity",
|
key = "activity",
|
||||||
@@ -382,6 +382,12 @@ class SettingsViewModelImpl(
|
|||||||
title = UiText.Simple("Show alert after crash"),
|
title = UiText.Simple("Show alert after crash"),
|
||||||
text = UiText.Simple("Shows alert dialog with stacktrace after app crashed\n(it will be not shown if you perform crash manually)")
|
text = UiText.Simple("Shows alert dialog with stacktrace after app crashed\n(it will be not shown if you perform crash manually)")
|
||||||
)
|
)
|
||||||
|
val debugLongPollBackground = SettingsItem.Switch(
|
||||||
|
key = SettingsKeys.KEY_FEATURES_LONG_POLL_IN_BACKGROUND,
|
||||||
|
defaultValue = SettingsKeys.DEFAULT_VALUE_FEATURES_LONG_POLL_IN_BACKGROUND,
|
||||||
|
title = UiText.Resource(UiR.string.settings_features_long_poll_in_background_title),
|
||||||
|
text = UiText.Resource(UiR.string.settings_features_long_poll_in_background_summary)
|
||||||
|
)
|
||||||
val debugUseBlur = SettingsItem.Switch(
|
val debugUseBlur = SettingsItem.Switch(
|
||||||
key = SettingsKeys.KEY_APPEARANCE_USE_BLUR,
|
key = SettingsKeys.KEY_APPEARANCE_USE_BLUR,
|
||||||
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR,
|
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_APPEARANCE_USE_BLUR,
|
||||||
@@ -394,6 +400,11 @@ class SettingsViewModelImpl(
|
|||||||
text = UiText.Simple("Show emoji button in chat panel"),
|
text = UiText.Simple("Show emoji button in chat panel"),
|
||||||
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
defaultValue = SettingsKeys.DEFAULT_VALUE_KEY_SHOW_EMOJI_BUTTON
|
||||||
)
|
)
|
||||||
|
val debugShowTimeInActionMessages = SettingsItem.Switch(
|
||||||
|
key = SettingsKeys.KEY_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||||
|
defaultValue = SettingsKeys.DEFAULT_VALUE_APPEARANCE_SHOW_TIME_IN_ACTION_MESSAGES,
|
||||||
|
title = UiText.Simple("Show time in action messages")
|
||||||
|
)
|
||||||
|
|
||||||
val debugHideDebugList = SettingsItem.TitleText(
|
val debugHideDebugList = SettingsItem.TitleText(
|
||||||
key = SettingsKeys.KEY_DEBUG_HIDE_DEBUG_LIST,
|
key = SettingsKeys.KEY_DEBUG_HIDE_DEBUG_LIST,
|
||||||
@@ -432,7 +443,8 @@ class SettingsViewModelImpl(
|
|||||||
debugShowCrashAlert,
|
debugShowCrashAlert,
|
||||||
debugLongPollBackground,
|
debugLongPollBackground,
|
||||||
debugUseBlur,
|
debugUseBlur,
|
||||||
debugShowEmojiButton
|
debugShowEmojiButton,
|
||||||
|
debugShowTimeInActionMessages
|
||||||
).forEach(debugList::add)
|
).forEach(debugList::add)
|
||||||
|
|
||||||
debugList += debugHideDebugList
|
debugList += debugHideDebugList
|
||||||
|
|||||||
Reference in New Issue
Block a user