forked from melod1n/fast-messenger
editing messages
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package com.meloda.fast.api
|
||||
|
||||
import com.meloda.fast.api.model.attachments.*
|
||||
|
||||
object VKConstants {
|
||||
|
||||
const val GROUP_FIELDS = "description,members_count,counters,status,verified"
|
||||
@@ -35,4 +37,15 @@ object VKConstants {
|
||||
const val PASSWORD = "password"
|
||||
}
|
||||
}
|
||||
|
||||
val restrictedToEditAttachments = listOf(
|
||||
VkCall::class.java,
|
||||
VkCurator::class.java,
|
||||
VkEvent::class.java,
|
||||
VkGift::class.java,
|
||||
VkGraffiti::class.java,
|
||||
VkGroupCall::class.java,
|
||||
VkStory::class.java,
|
||||
VkVoiceMessage::class.java
|
||||
)
|
||||
}
|
||||
@@ -17,6 +17,30 @@ import com.meloda.fast.api.model.base.attachments.BaseVkAttachmentItem
|
||||
|
||||
object VkUtils {
|
||||
|
||||
fun <T> attachmentToString(
|
||||
attachmentClass: Class<T>,
|
||||
id: Int,
|
||||
ownerId: Int,
|
||||
withAccessKey: Boolean,
|
||||
accessKey: String?
|
||||
): String {
|
||||
val type = when (attachmentClass) {
|
||||
VkAudio::class.java -> "audio"
|
||||
VkFile::class.java -> "doc"
|
||||
VkVideo::class.java -> "video"
|
||||
VkPhoto::class.java -> "photo"
|
||||
else -> throw IllegalArgumentException("unknown attachment class: $attachmentClass")
|
||||
}
|
||||
|
||||
val result = StringBuilder(type).append(ownerId).append('_').append(id)
|
||||
if (withAccessKey && !accessKey.isNullOrBlank()) {
|
||||
result.append('_')
|
||||
result.append(accessKey)
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
|
||||
fun getMessageUser(message: VkMessage, profiles: Map<Int, VkUser>): VkUser? {
|
||||
return (if (!message.isUser()) null
|
||||
else profiles[message.fromId]).also { message.user.value = it }
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.meloda.fast.api.UserConfig
|
||||
import com.meloda.fast.api.VKConstants
|
||||
import com.meloda.fast.api.model.attachments.VkAttachment
|
||||
import com.meloda.fast.base.adapter.SelectableItem
|
||||
import com.meloda.fast.util.TimeUtils
|
||||
@@ -15,8 +16,8 @@ import kotlinx.parcelize.Parcelize
|
||||
@Parcelize
|
||||
data class VkMessage(
|
||||
@PrimaryKey(autoGenerate = false)
|
||||
val id: Int,
|
||||
val text: String? = null,
|
||||
var id: Int,
|
||||
var text: String? = null,
|
||||
val isOut: Boolean,
|
||||
val peerId: Int,
|
||||
val fromId: Int,
|
||||
@@ -28,7 +29,7 @@ data class VkMessage(
|
||||
val actionConversationMessageId: Int? = null,
|
||||
val actionMessage: String? = null,
|
||||
val geoType: String? = null,
|
||||
val important: Boolean = false,
|
||||
var important: Boolean = false,
|
||||
|
||||
var forwards: List<VkMessage>? = null,
|
||||
var attachments: List<VkAttachment>? = null,
|
||||
@@ -62,43 +63,11 @@ data class VkMessage(
|
||||
|
||||
fun canEdit() =
|
||||
fromId == UserConfig.userId &&
|
||||
(attachments == null || !VKConstants.restrictedToEditAttachments.contains(
|
||||
attachments!![0].javaClass
|
||||
)) &&
|
||||
(System.currentTimeMillis() / 1000 - date.toLong() < TimeUtils.ONE_DAY_IN_SECONDS)
|
||||
|
||||
fun copyMessage(
|
||||
id: Int = this.id,
|
||||
text: String? = this.text,
|
||||
isOut: Boolean = this.isOut,
|
||||
peerId: Int = this.peerId,
|
||||
fromId: Int = this.fromId,
|
||||
date: Int = this.date,
|
||||
randomId: Int = this.randomId,
|
||||
action: String? = this.action,
|
||||
actionMemberId: Int? = this.actionMemberId,
|
||||
actionText: String? = this.actionText,
|
||||
actionConversationMessageId: Int? = this.actionConversationMessageId,
|
||||
actionMessage: String? = this.actionMessage,
|
||||
geoType: String? = this.geoType,
|
||||
important: Boolean = this.important
|
||||
) = VkMessage(
|
||||
id = id,
|
||||
text = text,
|
||||
isOut = isOut,
|
||||
peerId = peerId,
|
||||
fromId = fromId,
|
||||
date = date,
|
||||
randomId = randomId,
|
||||
action = action,
|
||||
actionMemberId = actionMemberId,
|
||||
actionText = actionText,
|
||||
actionConversationMessageId = actionConversationMessageId,
|
||||
actionMessage = actionMessage,
|
||||
geoType = geoType,
|
||||
important = important
|
||||
).also {
|
||||
it.attachments = attachments
|
||||
it.forwards = forwards
|
||||
}
|
||||
|
||||
enum class Action(val value: String) {
|
||||
CHAT_CREATE("chat_create"),
|
||||
CHAT_PHOTO_UPDATE("chat_photo_update"),
|
||||
|
||||
@@ -4,4 +4,8 @@ import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
open class VkAttachment : Parcelable
|
||||
open class VkAttachment : Parcelable {
|
||||
|
||||
open fun asString(withAccessKey: Boolean = true) = ""
|
||||
|
||||
}
|
||||
@@ -1,17 +1,28 @@
|
||||
package com.meloda.fast.api.model.attachments
|
||||
|
||||
import com.meloda.fast.api.VkUtils
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class VkAudio(
|
||||
val id: Int,
|
||||
val ownerId: Int,
|
||||
val title: String,
|
||||
val artist: String,
|
||||
val url: String,
|
||||
val duration: Int
|
||||
val duration: Int,
|
||||
val accessKey: String?
|
||||
) : VkAttachment() {
|
||||
|
||||
@IgnoredOnParcel
|
||||
val className: String = this::class.java.name
|
||||
|
||||
override fun asString(withAccessKey: Boolean) = VkUtils.attachmentToString(
|
||||
attachmentClass = this::class.java,
|
||||
id = id,
|
||||
ownerId = ownerId,
|
||||
withAccessKey = withAccessKey,
|
||||
accessKey = accessKey
|
||||
)
|
||||
}
|
||||
@@ -1,17 +1,28 @@
|
||||
package com.meloda.fast.api.model.attachments
|
||||
|
||||
import com.meloda.fast.api.VkUtils
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class VkFile(
|
||||
val id: Int,
|
||||
val ownerId: Int,
|
||||
val title: String,
|
||||
val ext: String,
|
||||
val size: Int,
|
||||
val url: String
|
||||
val url: String,
|
||||
val accessKey: String?
|
||||
) : VkAttachment() {
|
||||
|
||||
@IgnoredOnParcel
|
||||
val className: String = this::class.java.name
|
||||
|
||||
override fun asString(withAccessKey: Boolean) = VkUtils.attachmentToString(
|
||||
attachmentClass = this::class.java,
|
||||
id = id,
|
||||
ownerId = ownerId,
|
||||
withAccessKey = withAccessKey,
|
||||
accessKey = accessKey
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.meloda.fast.api.model.attachments
|
||||
|
||||
import androidx.room.Ignore
|
||||
import com.meloda.fast.api.VkUtils
|
||||
import com.meloda.fast.api.model.base.attachments.BaseVkPhoto
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@@ -39,6 +40,14 @@ data class VkPhoto(
|
||||
@IgnoredOnParcel
|
||||
val className: String = this::class.java.name
|
||||
|
||||
override fun asString(withAccessKey: Boolean) = VkUtils.attachmentToString(
|
||||
attachmentClass = this::class.java,
|
||||
id = id,
|
||||
ownerId = ownerId,
|
||||
withAccessKey = withAccessKey,
|
||||
accessKey = accessKey
|
||||
)
|
||||
|
||||
fun getMaxSize(): BaseVkPhoto.Size? {
|
||||
return getSizeOrSmaller(sizesChars.peek())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.meloda.fast.api.model.attachments
|
||||
|
||||
import com.meloda.fast.api.VkUtils
|
||||
import com.meloda.fast.api.model.base.attachments.BaseVkVideo
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@@ -7,8 +8,10 @@ import kotlinx.parcelize.Parcelize
|
||||
@Parcelize
|
||||
data class VkVideo(
|
||||
val id: Int,
|
||||
val ownerId: Int,
|
||||
val images: List<BaseVkVideo.Image>,
|
||||
val firstFrames: List<BaseVkVideo.FirstFrame>?
|
||||
val firstFrames: List<BaseVkVideo.FirstFrame>?,
|
||||
val accessKey: String?
|
||||
) : VkAttachment() {
|
||||
|
||||
@IgnoredOnParcel
|
||||
@@ -18,4 +21,12 @@ data class VkVideo(
|
||||
return images.find { it.width == width }
|
||||
}
|
||||
|
||||
override fun asString(withAccessKey: Boolean) = VkUtils.attachmentToString(
|
||||
attachmentClass = this::class.java,
|
||||
id = id,
|
||||
ownerId = ownerId,
|
||||
withAccessKey = withAccessKey,
|
||||
accessKey = accessKey
|
||||
)
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ data class BaseVkAudio(
|
||||
val url: String,
|
||||
val date: Int,
|
||||
val owner_id: Int,
|
||||
val access_key: String,
|
||||
val access_key: String?,
|
||||
val is_explicit: Boolean,
|
||||
val is_focus_track: Boolean,
|
||||
val is_licensed: Boolean,
|
||||
@@ -27,10 +27,12 @@ data class BaseVkAudio(
|
||||
|
||||
fun asVkAudio() = VkAudio(
|
||||
id = id,
|
||||
ownerId = owner_id,
|
||||
title = title,
|
||||
artist = artist,
|
||||
url = url,
|
||||
duration = duration
|
||||
duration = duration,
|
||||
accessKey = access_key
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
|
||||
@@ -16,16 +16,18 @@ data class BaseVkFile(
|
||||
val url: String,
|
||||
val preview: Preview?,
|
||||
val ic_licensed: Int,
|
||||
val access_key: String,
|
||||
val access_key: String?,
|
||||
val web_preview_url: String?
|
||||
) : BaseVkAttachment() {
|
||||
|
||||
fun asVkFile() = VkFile(
|
||||
id = id,
|
||||
ownerId = owner_id,
|
||||
title = title,
|
||||
ext = ext,
|
||||
url = url,
|
||||
size = size
|
||||
size = size,
|
||||
accessKey = access_key
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
|
||||
@@ -26,7 +26,7 @@ data class BaseVkVideo(
|
||||
val can_add_to_faves: Int,
|
||||
val can_add: Int,
|
||||
val can_attach_link: Int,
|
||||
val access_key: String,
|
||||
val access_key: String?,
|
||||
val owner_id: Int,
|
||||
val ov_id: String,
|
||||
val is_favorite: Boolean,
|
||||
@@ -40,8 +40,10 @@ data class BaseVkVideo(
|
||||
|
||||
fun asVkVideo() = VkVideo(
|
||||
id = id,
|
||||
ownerId = owner_id,
|
||||
images = image,
|
||||
firstFrames = first_frame
|
||||
firstFrames = first_frame,
|
||||
accessKey = access_key
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
|
||||
@@ -31,6 +31,7 @@ object VkUrls {
|
||||
const val Pin = "$API/messages.pin"
|
||||
const val Unpin = "$API/messages.unpin"
|
||||
const val Delete = "$API/messages.delete"
|
||||
const val Edit = "$API/messages.edit"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ class MessagesDataSource @Inject constructor(
|
||||
suspend fun delete(params: MessagesDeleteRequest) =
|
||||
repo.delete(params.map)
|
||||
|
||||
suspend fun edit(params: MessagesEditRequest) =
|
||||
repo.edit(params.map)
|
||||
|
||||
suspend fun store(messages: List<VkMessage>) = dao.insert(messages)
|
||||
|
||||
suspend fun getCached(peerId: Int) = dao.getByPeerId(peerId)
|
||||
|
||||
@@ -39,4 +39,8 @@ interface MessagesRepo {
|
||||
@POST(VkUrls.Messages.Delete)
|
||||
suspend fun delete(@FieldMap params: Map<String, String>): Answer<ApiResponse<Any>>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(VkUrls.Messages.Edit)
|
||||
suspend fun edit(@FieldMap params: Map<String, String>): Answer<ApiResponse<Any>>
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.meloda.fast.api.network.messages
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.meloda.fast.api.ApiExtensions.intString
|
||||
import com.meloda.fast.api.model.attachments.VkAttachment
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@@ -130,5 +131,38 @@ data class MessagesDeleteRequest(
|
||||
this["conversation_message_ids"] = it.joinToString { id -> id.toString() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class MessagesEditRequest(
|
||||
val peerId: Int,
|
||||
val messageId: Int,
|
||||
val message: String? = null,
|
||||
val lat: Float? = null,
|
||||
val lon: Float? = null,
|
||||
val attachments: List<VkAttachment>? = null,
|
||||
val notParseLinks: Boolean = false,
|
||||
val keepSnippets: Boolean = true,
|
||||
val keepForwardedMessages: Boolean = true
|
||||
) : Parcelable {
|
||||
|
||||
val map
|
||||
get() = mutableMapOf(
|
||||
"peer_id" to peerId.toString(),
|
||||
"message_id" to messageId.toString(),
|
||||
"dont_parse_links" to notParseLinks.intString,
|
||||
"keep_snippets" to keepSnippets.intString,
|
||||
"keep_forward_messages" to keepForwardedMessages.intString
|
||||
).apply {
|
||||
message?.let { this["message"] = it }
|
||||
lat?.let { this["lat"] = it.toString() }
|
||||
lon?.let { this["lon"] = it.toString() }
|
||||
attachments?.let {
|
||||
val attachments =
|
||||
if (it.isEmpty()) ""
|
||||
else it.joinToString(separator = ",") { attachment -> attachment.asString() }
|
||||
this["attachment"] = attachments
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -267,6 +267,15 @@ class MessagesHistoryAdapter constructor(
|
||||
return positions
|
||||
}
|
||||
|
||||
fun searchMessageIndex(messageId: Int): Int? {
|
||||
for (i in values.indices) {
|
||||
val message = values[i]
|
||||
if (message.id == messageId) return i
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val SERVICE = 1
|
||||
private const val HEADER = 0
|
||||
|
||||
@@ -51,7 +51,7 @@ class MessagesHistoryFragment :
|
||||
private val action = MutableLiveData<Action>()
|
||||
|
||||
private enum class Action {
|
||||
RECORD, SEND, EDIT
|
||||
RECORD, SEND, EDIT, DELETE
|
||||
}
|
||||
|
||||
private val user: VkUser? by lazy {
|
||||
@@ -167,12 +167,11 @@ class MessagesHistoryFragment :
|
||||
})
|
||||
|
||||
binding.message.doAfterTextChanged {
|
||||
val canSend =
|
||||
it.toString().isNotBlank()
|
||||
val canSend = it.toString().isNotBlank()
|
||||
|
||||
val newValue =
|
||||
val newValue: Action =
|
||||
when {
|
||||
attachmentController.isEditing -> Action.EDIT
|
||||
attachmentController.isEditing -> if (it.isNullOrBlank()) Action.DELETE else Action.EDIT
|
||||
canSend -> Action.SEND
|
||||
else -> Action.RECORD
|
||||
}
|
||||
@@ -203,11 +202,16 @@ class MessagesHistoryFragment :
|
||||
Action.EDIT -> {
|
||||
binding.action.setImageResource(R.drawable.ic_round_done_24)
|
||||
}
|
||||
Action.DELETE -> {
|
||||
binding.action.setImageResource(R.drawable.ic_trash_can_outline_24)
|
||||
}
|
||||
else -> return@observe
|
||||
}
|
||||
}
|
||||
|
||||
attachmentController.isPanelVisible.observe(viewLifecycleOwner) {
|
||||
if (it) binding.message.setSelection(binding.message.text.toString().length)
|
||||
|
||||
val layoutParams = binding.refreshLayout.layoutParams as CoordinatorLayout.LayoutParams
|
||||
layoutParams.bottomMargin =
|
||||
if (it) (binding.attachmentPanel.height / 1.5).roundToInt() else 0
|
||||
@@ -280,15 +284,16 @@ class MessagesHistoryFragment :
|
||||
}
|
||||
|
||||
private fun performAction() {
|
||||
if (action.value == Action.RECORD) {
|
||||
return
|
||||
} else if (action.value == Action.SEND) {
|
||||
when (action.value) {
|
||||
Action.RECORD -> {
|
||||
}
|
||||
Action.SEND -> {
|
||||
val messageText = binding.message.text.toString().trim()
|
||||
if (messageText.isBlank()) return
|
||||
|
||||
val date = System.currentTimeMillis()
|
||||
|
||||
var message = VkMessage(
|
||||
val message = VkMessage(
|
||||
id = -1,
|
||||
text = messageText,
|
||||
isOut = true,
|
||||
@@ -312,7 +317,25 @@ class MessagesHistoryFragment :
|
||||
message = messageText,
|
||||
randomId = 0,
|
||||
replyTo = replyMessage?.id
|
||||
) { message = message.copyMessage(id = it) }
|
||||
) { message.id = it }
|
||||
}
|
||||
Action.EDIT -> {
|
||||
val message = attachmentController.message.value ?: return
|
||||
val messageText = binding.message.text.toString().trim()
|
||||
|
||||
attachmentController.message.value = null
|
||||
|
||||
viewModel.editMessage(
|
||||
originalMessage = message,
|
||||
peerId = conversation.id,
|
||||
messageId = message.id,
|
||||
message = messageText,
|
||||
attachments = message.attachments
|
||||
)
|
||||
}
|
||||
Action.DELETE -> attachmentController.message.value?.let {
|
||||
showDeleteMessageDialog(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +351,7 @@ class MessagesHistoryFragment :
|
||||
is MessagesPin -> conversation.pinnedMessage = event.message
|
||||
is MessagesUnpin -> conversation.pinnedMessage = null
|
||||
is MessagesDelete -> deleteMessages(event)
|
||||
is MessagesEdit -> editMessage(event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,14 +401,13 @@ class MessagesHistoryFragment :
|
||||
|
||||
for (i in adapter.values.indices) {
|
||||
val message = adapter.values[i]
|
||||
message.important = event.important
|
||||
if (event.messagesIds.contains(message.id)) {
|
||||
if (!changed) changed = true
|
||||
|
||||
positions.add(i)
|
||||
|
||||
adapter.values[i] = message.copyMessage(
|
||||
important = event.important
|
||||
)
|
||||
adapter.values[i] = message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,17 +555,22 @@ class MessagesHistoryFragment :
|
||||
else R.string.message_mark_as_spam
|
||||
)
|
||||
|
||||
binding.check.isEnabled = !message.isOut || message.canEdit()
|
||||
binding.check.isEnabled =
|
||||
(conversation.id != UserConfig.userId) && (!message.isOut || message.canEdit())
|
||||
|
||||
if (conversation.id == UserConfig.userId) binding.check.isChecked = true
|
||||
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.confirm_delete_message)
|
||||
.setView(binding.root)
|
||||
.setPositiveButton(R.string.action_delete) { _, _ ->
|
||||
attachmentController.message.value = null
|
||||
|
||||
viewModel.deleteMessage(
|
||||
peerId = conversation.id,
|
||||
messagesIds = listOf(message.id),
|
||||
isSpam = if (message.isOut) null else binding.check.isChecked,
|
||||
deleteForAll = if (!message.isOut || !message.canEdit()) null else binding.check.isChecked
|
||||
deleteForAll = if (!binding.check.isEnabled) null else binding.check.isChecked
|
||||
)
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
@@ -555,6 +583,13 @@ class MessagesHistoryFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun editMessage(event: MessagesEdit) {
|
||||
adapter.searchMessageIndex(event.message.id)?.let { index ->
|
||||
adapter.values[index] = event.message
|
||||
adapter.notifyItemChanged(index)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AttachmentPanelController {
|
||||
val isPanelVisible = MutableLiveData(false)
|
||||
val message = MutableLiveData<VkMessage?>()
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.meloda.fast.api.model.VkConversation
|
||||
import com.meloda.fast.api.model.VkGroup
|
||||
import com.meloda.fast.api.model.VkMessage
|
||||
import com.meloda.fast.api.model.VkUser
|
||||
import com.meloda.fast.api.model.attachments.VkAttachment
|
||||
import com.meloda.fast.api.network.messages.*
|
||||
import com.meloda.fast.base.viewmodel.BaseViewModel
|
||||
import com.meloda.fast.base.viewmodel.VkEvent
|
||||
@@ -173,6 +174,31 @@ class MessagesHistoryViewModel @Inject constructor(
|
||||
)
|
||||
}, onAnswer = { sendEvent(MessagesDelete(messagesIds = messagesIds ?: listOf())) })
|
||||
}
|
||||
|
||||
fun editMessage(
|
||||
originalMessage: VkMessage,
|
||||
peerId: Int,
|
||||
messageId: Int,
|
||||
message: String? = null,
|
||||
attachments: List<VkAttachment>? = null
|
||||
) = viewModelScope.launch {
|
||||
makeJob(
|
||||
{
|
||||
messages.edit(
|
||||
MessagesEditRequest(
|
||||
peerId = peerId,
|
||||
messageId = messageId,
|
||||
message = message,
|
||||
attachments = attachments
|
||||
)
|
||||
)
|
||||
},
|
||||
onAnswer = {
|
||||
originalMessage.text = message
|
||||
sendEvent(MessagesEdit(originalMessage))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class MessagesLoaded(
|
||||
@@ -198,3 +224,6 @@ data class MessagesDelete(
|
||||
val messagesIds: List<Int>
|
||||
) : VkEvent()
|
||||
|
||||
data class MessagesEdit(
|
||||
val message: VkMessage
|
||||
) : VkEvent()
|
||||
@@ -213,7 +213,7 @@ class MessagesPreparator constructor(
|
||||
} else {
|
||||
text.isVisible = true
|
||||
bubble.isVisible = true
|
||||
text.text = VkUtils.prepareMessageText(message.text)
|
||||
text.text = VkUtils.prepareMessageText(message.text ?: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" />
|
||||
</vector>
|
||||
Reference in New Issue
Block a user