editing messages
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
package com.meloda.fast.api
|
package com.meloda.fast.api
|
||||||
|
|
||||||
|
import com.meloda.fast.api.model.attachments.*
|
||||||
|
|
||||||
object VKConstants {
|
object VKConstants {
|
||||||
|
|
||||||
const val GROUP_FIELDS = "description,members_count,counters,status,verified"
|
const val GROUP_FIELDS = "description,members_count,counters,status,verified"
|
||||||
@@ -35,4 +37,15 @@ object VKConstants {
|
|||||||
const val PASSWORD = "password"
|
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 {
|
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? {
|
fun getMessageUser(message: VkMessage, profiles: Map<Int, VkUser>): VkUser? {
|
||||||
return (if (!message.isUser()) null
|
return (if (!message.isUser()) null
|
||||||
else profiles[message.fromId]).also { message.user.value = it }
|
else profiles[message.fromId]).also { message.user.value = it }
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import androidx.room.Entity
|
|||||||
import androidx.room.Ignore
|
import androidx.room.Ignore
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.meloda.fast.api.UserConfig
|
import com.meloda.fast.api.UserConfig
|
||||||
|
import com.meloda.fast.api.VKConstants
|
||||||
import com.meloda.fast.api.model.attachments.VkAttachment
|
import com.meloda.fast.api.model.attachments.VkAttachment
|
||||||
import com.meloda.fast.base.adapter.SelectableItem
|
import com.meloda.fast.base.adapter.SelectableItem
|
||||||
import com.meloda.fast.util.TimeUtils
|
import com.meloda.fast.util.TimeUtils
|
||||||
@@ -15,8 +16,8 @@ import kotlinx.parcelize.Parcelize
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
data class VkMessage(
|
data class VkMessage(
|
||||||
@PrimaryKey(autoGenerate = false)
|
@PrimaryKey(autoGenerate = false)
|
||||||
val id: Int,
|
var id: Int,
|
||||||
val text: String? = null,
|
var text: String? = null,
|
||||||
val isOut: Boolean,
|
val isOut: Boolean,
|
||||||
val peerId: Int,
|
val peerId: Int,
|
||||||
val fromId: Int,
|
val fromId: Int,
|
||||||
@@ -28,7 +29,7 @@ data class VkMessage(
|
|||||||
val actionConversationMessageId: Int? = null,
|
val actionConversationMessageId: Int? = null,
|
||||||
val actionMessage: String? = null,
|
val actionMessage: String? = null,
|
||||||
val geoType: String? = null,
|
val geoType: String? = null,
|
||||||
val important: Boolean = false,
|
var important: Boolean = false,
|
||||||
|
|
||||||
var forwards: List<VkMessage>? = null,
|
var forwards: List<VkMessage>? = null,
|
||||||
var attachments: List<VkAttachment>? = null,
|
var attachments: List<VkAttachment>? = null,
|
||||||
@@ -62,43 +63,11 @@ data class VkMessage(
|
|||||||
|
|
||||||
fun canEdit() =
|
fun canEdit() =
|
||||||
fromId == UserConfig.userId &&
|
fromId == UserConfig.userId &&
|
||||||
|
(attachments == null || !VKConstants.restrictedToEditAttachments.contains(
|
||||||
|
attachments!![0].javaClass
|
||||||
|
)) &&
|
||||||
(System.currentTimeMillis() / 1000 - date.toLong() < TimeUtils.ONE_DAY_IN_SECONDS)
|
(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) {
|
enum class Action(val value: String) {
|
||||||
CHAT_CREATE("chat_create"),
|
CHAT_CREATE("chat_create"),
|
||||||
CHAT_PHOTO_UPDATE("chat_photo_update"),
|
CHAT_PHOTO_UPDATE("chat_photo_update"),
|
||||||
|
|||||||
@@ -4,4 +4,8 @@ import android.os.Parcelable
|
|||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.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
|
package com.meloda.fast.api.model.attachments
|
||||||
|
|
||||||
|
import com.meloda.fast.api.VkUtils
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class VkAudio(
|
data class VkAudio(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
|
val ownerId: Int,
|
||||||
val title: String,
|
val title: String,
|
||||||
val artist: String,
|
val artist: String,
|
||||||
val url: String,
|
val url: String,
|
||||||
val duration: Int
|
val duration: Int,
|
||||||
|
val accessKey: String?
|
||||||
) : VkAttachment() {
|
) : VkAttachment() {
|
||||||
|
|
||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
val className: String = this::class.java.name
|
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
|
package com.meloda.fast.api.model.attachments
|
||||||
|
|
||||||
|
import com.meloda.fast.api.VkUtils
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class VkFile(
|
data class VkFile(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
|
val ownerId: Int,
|
||||||
val title: String,
|
val title: String,
|
||||||
val ext: String,
|
val ext: String,
|
||||||
val size: Int,
|
val size: Int,
|
||||||
val url: String
|
val url: String,
|
||||||
|
val accessKey: String?
|
||||||
) : VkAttachment() {
|
) : VkAttachment() {
|
||||||
|
|
||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
val className: String = this::class.java.name
|
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
|
package com.meloda.fast.api.model.attachments
|
||||||
|
|
||||||
import androidx.room.Ignore
|
import androidx.room.Ignore
|
||||||
|
import com.meloda.fast.api.VkUtils
|
||||||
import com.meloda.fast.api.model.base.attachments.BaseVkPhoto
|
import com.meloda.fast.api.model.base.attachments.BaseVkPhoto
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
@@ -39,6 +40,14 @@ data class VkPhoto(
|
|||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
val className: String = this::class.java.name
|
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? {
|
fun getMaxSize(): BaseVkPhoto.Size? {
|
||||||
return getSizeOrSmaller(sizesChars.peek())
|
return getSizeOrSmaller(sizesChars.peek())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.meloda.fast.api.model.attachments
|
package com.meloda.fast.api.model.attachments
|
||||||
|
|
||||||
|
import com.meloda.fast.api.VkUtils
|
||||||
import com.meloda.fast.api.model.base.attachments.BaseVkVideo
|
import com.meloda.fast.api.model.base.attachments.BaseVkVideo
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
@@ -7,8 +8,10 @@ import kotlinx.parcelize.Parcelize
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
data class VkVideo(
|
data class VkVideo(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
|
val ownerId: Int,
|
||||||
val images: List<BaseVkVideo.Image>,
|
val images: List<BaseVkVideo.Image>,
|
||||||
val firstFrames: List<BaseVkVideo.FirstFrame>?
|
val firstFrames: List<BaseVkVideo.FirstFrame>?,
|
||||||
|
val accessKey: String?
|
||||||
) : VkAttachment() {
|
) : VkAttachment() {
|
||||||
|
|
||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
@@ -18,4 +21,12 @@ data class VkVideo(
|
|||||||
return images.find { it.width == width }
|
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 url: String,
|
||||||
val date: Int,
|
val date: Int,
|
||||||
val owner_id: Int,
|
val owner_id: Int,
|
||||||
val access_key: String,
|
val access_key: String?,
|
||||||
val is_explicit: Boolean,
|
val is_explicit: Boolean,
|
||||||
val is_focus_track: Boolean,
|
val is_focus_track: Boolean,
|
||||||
val is_licensed: Boolean,
|
val is_licensed: Boolean,
|
||||||
@@ -27,10 +27,12 @@ data class BaseVkAudio(
|
|||||||
|
|
||||||
fun asVkAudio() = VkAudio(
|
fun asVkAudio() = VkAudio(
|
||||||
id = id,
|
id = id,
|
||||||
|
ownerId = owner_id,
|
||||||
title = title,
|
title = title,
|
||||||
artist = artist,
|
artist = artist,
|
||||||
url = url,
|
url = url,
|
||||||
duration = duration
|
duration = duration,
|
||||||
|
accessKey = access_key
|
||||||
)
|
)
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
|||||||
@@ -16,16 +16,18 @@ data class BaseVkFile(
|
|||||||
val url: String,
|
val url: String,
|
||||||
val preview: Preview?,
|
val preview: Preview?,
|
||||||
val ic_licensed: Int,
|
val ic_licensed: Int,
|
||||||
val access_key: String,
|
val access_key: String?,
|
||||||
val web_preview_url: String?
|
val web_preview_url: String?
|
||||||
) : BaseVkAttachment() {
|
) : BaseVkAttachment() {
|
||||||
|
|
||||||
fun asVkFile() = VkFile(
|
fun asVkFile() = VkFile(
|
||||||
id = id,
|
id = id,
|
||||||
|
ownerId = owner_id,
|
||||||
title = title,
|
title = title,
|
||||||
ext = ext,
|
ext = ext,
|
||||||
url = url,
|
url = url,
|
||||||
size = size
|
size = size,
|
||||||
|
accessKey = access_key
|
||||||
)
|
)
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ data class BaseVkVideo(
|
|||||||
val can_add_to_faves: Int,
|
val can_add_to_faves: Int,
|
||||||
val can_add: Int,
|
val can_add: Int,
|
||||||
val can_attach_link: Int,
|
val can_attach_link: Int,
|
||||||
val access_key: String,
|
val access_key: String?,
|
||||||
val owner_id: Int,
|
val owner_id: Int,
|
||||||
val ov_id: String,
|
val ov_id: String,
|
||||||
val is_favorite: Boolean,
|
val is_favorite: Boolean,
|
||||||
@@ -40,8 +40,10 @@ data class BaseVkVideo(
|
|||||||
|
|
||||||
fun asVkVideo() = VkVideo(
|
fun asVkVideo() = VkVideo(
|
||||||
id = id,
|
id = id,
|
||||||
|
ownerId = owner_id,
|
||||||
images = image,
|
images = image,
|
||||||
firstFrames = first_frame
|
firstFrames = first_frame,
|
||||||
|
accessKey = access_key
|
||||||
)
|
)
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ object VkUrls {
|
|||||||
const val Pin = "$API/messages.pin"
|
const val Pin = "$API/messages.pin"
|
||||||
const val Unpin = "$API/messages.unpin"
|
const val Unpin = "$API/messages.unpin"
|
||||||
const val Delete = "$API/messages.delete"
|
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) =
|
suspend fun delete(params: MessagesDeleteRequest) =
|
||||||
repo.delete(params.map)
|
repo.delete(params.map)
|
||||||
|
|
||||||
|
suspend fun edit(params: MessagesEditRequest) =
|
||||||
|
repo.edit(params.map)
|
||||||
|
|
||||||
suspend fun store(messages: List<VkMessage>) = dao.insert(messages)
|
suspend fun store(messages: List<VkMessage>) = dao.insert(messages)
|
||||||
|
|
||||||
suspend fun getCached(peerId: Int) = dao.getByPeerId(peerId)
|
suspend fun getCached(peerId: Int) = dao.getByPeerId(peerId)
|
||||||
|
|||||||
@@ -39,4 +39,8 @@ interface MessagesRepo {
|
|||||||
@POST(VkUrls.Messages.Delete)
|
@POST(VkUrls.Messages.Delete)
|
||||||
suspend fun delete(@FieldMap params: Map<String, String>): Answer<ApiResponse<Any>>
|
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 android.os.Parcelable
|
||||||
import com.meloda.fast.api.ApiExtensions.intString
|
import com.meloda.fast.api.ApiExtensions.intString
|
||||||
|
import com.meloda.fast.api.model.attachments.VkAttachment
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@@ -130,5 +131,38 @@ data class MessagesDeleteRequest(
|
|||||||
this["conversation_message_ids"] = it.joinToString { id -> id.toString() }
|
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
|
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 {
|
companion object {
|
||||||
private const val SERVICE = 1
|
private const val SERVICE = 1
|
||||||
private const val HEADER = 0
|
private const val HEADER = 0
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class MessagesHistoryFragment :
|
|||||||
private val action = MutableLiveData<Action>()
|
private val action = MutableLiveData<Action>()
|
||||||
|
|
||||||
private enum class Action {
|
private enum class Action {
|
||||||
RECORD, SEND, EDIT
|
RECORD, SEND, EDIT, DELETE
|
||||||
}
|
}
|
||||||
|
|
||||||
private val user: VkUser? by lazy {
|
private val user: VkUser? by lazy {
|
||||||
@@ -167,12 +167,11 @@ class MessagesHistoryFragment :
|
|||||||
})
|
})
|
||||||
|
|
||||||
binding.message.doAfterTextChanged {
|
binding.message.doAfterTextChanged {
|
||||||
val canSend =
|
val canSend = it.toString().isNotBlank()
|
||||||
it.toString().isNotBlank()
|
|
||||||
|
|
||||||
val newValue =
|
val newValue: Action =
|
||||||
when {
|
when {
|
||||||
attachmentController.isEditing -> Action.EDIT
|
attachmentController.isEditing -> if (it.isNullOrBlank()) Action.DELETE else Action.EDIT
|
||||||
canSend -> Action.SEND
|
canSend -> Action.SEND
|
||||||
else -> Action.RECORD
|
else -> Action.RECORD
|
||||||
}
|
}
|
||||||
@@ -203,11 +202,16 @@ class MessagesHistoryFragment :
|
|||||||
Action.EDIT -> {
|
Action.EDIT -> {
|
||||||
binding.action.setImageResource(R.drawable.ic_round_done_24)
|
binding.action.setImageResource(R.drawable.ic_round_done_24)
|
||||||
}
|
}
|
||||||
|
Action.DELETE -> {
|
||||||
|
binding.action.setImageResource(R.drawable.ic_trash_can_outline_24)
|
||||||
|
}
|
||||||
else -> return@observe
|
else -> return@observe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attachmentController.isPanelVisible.observe(viewLifecycleOwner) {
|
attachmentController.isPanelVisible.observe(viewLifecycleOwner) {
|
||||||
|
if (it) binding.message.setSelection(binding.message.text.toString().length)
|
||||||
|
|
||||||
val layoutParams = binding.refreshLayout.layoutParams as CoordinatorLayout.LayoutParams
|
val layoutParams = binding.refreshLayout.layoutParams as CoordinatorLayout.LayoutParams
|
||||||
layoutParams.bottomMargin =
|
layoutParams.bottomMargin =
|
||||||
if (it) (binding.attachmentPanel.height / 1.5).roundToInt() else 0
|
if (it) (binding.attachmentPanel.height / 1.5).roundToInt() else 0
|
||||||
@@ -280,39 +284,58 @@ class MessagesHistoryFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun performAction() {
|
private fun performAction() {
|
||||||
if (action.value == Action.RECORD) {
|
when (action.value) {
|
||||||
return
|
Action.RECORD -> {
|
||||||
} else if (action.value == Action.SEND) {
|
}
|
||||||
val messageText = binding.message.text.toString().trim()
|
Action.SEND -> {
|
||||||
if (messageText.isBlank()) return
|
val messageText = binding.message.text.toString().trim()
|
||||||
|
if (messageText.isBlank()) return
|
||||||
|
|
||||||
val date = System.currentTimeMillis()
|
val date = System.currentTimeMillis()
|
||||||
|
|
||||||
var message = VkMessage(
|
val message = VkMessage(
|
||||||
id = -1,
|
id = -1,
|
||||||
text = messageText,
|
text = messageText,
|
||||||
isOut = true,
|
isOut = true,
|
||||||
peerId = conversation.id,
|
peerId = conversation.id,
|
||||||
fromId = UserConfig.userId,
|
fromId = UserConfig.userId,
|
||||||
date = (date / 1000).toInt(),
|
date = (date / 1000).toInt(),
|
||||||
randomId = 0,
|
randomId = 0,
|
||||||
replyMessage = attachmentController.message.value
|
replyMessage = attachmentController.message.value
|
||||||
)
|
)
|
||||||
|
|
||||||
adapter.add(message)
|
adapter.add(message)
|
||||||
adapter.notifyItemInserted(adapter.actualSize - 1)
|
adapter.notifyItemInserted(adapter.actualSize - 1)
|
||||||
binding.recyclerView.smoothScrollToPosition(adapter.lastPosition)
|
binding.recyclerView.smoothScrollToPosition(adapter.lastPosition)
|
||||||
binding.message.clear()
|
binding.message.clear()
|
||||||
|
|
||||||
val replyMessage = attachmentController.message.value
|
val replyMessage = attachmentController.message.value
|
||||||
attachmentController.message.value = null
|
attachmentController.message.value = null
|
||||||
|
|
||||||
viewModel.sendMessage(
|
viewModel.sendMessage(
|
||||||
peerId = conversation.id,
|
peerId = conversation.id,
|
||||||
message = messageText,
|
message = messageText,
|
||||||
randomId = 0,
|
randomId = 0,
|
||||||
replyTo = replyMessage?.id
|
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 MessagesPin -> conversation.pinnedMessage = event.message
|
||||||
is MessagesUnpin -> conversation.pinnedMessage = null
|
is MessagesUnpin -> conversation.pinnedMessage = null
|
||||||
is MessagesDelete -> deleteMessages(event)
|
is MessagesDelete -> deleteMessages(event)
|
||||||
|
is MessagesEdit -> editMessage(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,14 +401,13 @@ class MessagesHistoryFragment :
|
|||||||
|
|
||||||
for (i in adapter.values.indices) {
|
for (i in adapter.values.indices) {
|
||||||
val message = adapter.values[i]
|
val message = adapter.values[i]
|
||||||
|
message.important = event.important
|
||||||
if (event.messagesIds.contains(message.id)) {
|
if (event.messagesIds.contains(message.id)) {
|
||||||
if (!changed) changed = true
|
if (!changed) changed = true
|
||||||
|
|
||||||
positions.add(i)
|
positions.add(i)
|
||||||
|
|
||||||
adapter.values[i] = message.copyMessage(
|
adapter.values[i] = message
|
||||||
important = event.important
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,17 +555,22 @@ class MessagesHistoryFragment :
|
|||||||
else R.string.message_mark_as_spam
|
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())
|
MaterialAlertDialogBuilder(requireContext())
|
||||||
.setTitle(R.string.confirm_delete_message)
|
.setTitle(R.string.confirm_delete_message)
|
||||||
.setView(binding.root)
|
.setView(binding.root)
|
||||||
.setPositiveButton(R.string.action_delete) { _, _ ->
|
.setPositiveButton(R.string.action_delete) { _, _ ->
|
||||||
|
attachmentController.message.value = null
|
||||||
|
|
||||||
viewModel.deleteMessage(
|
viewModel.deleteMessage(
|
||||||
peerId = conversation.id,
|
peerId = conversation.id,
|
||||||
messagesIds = listOf(message.id),
|
messagesIds = listOf(message.id),
|
||||||
isSpam = if (message.isOut) null else binding.check.isChecked,
|
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)
|
.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 {
|
private inner class AttachmentPanelController {
|
||||||
val isPanelVisible = MutableLiveData(false)
|
val isPanelVisible = MutableLiveData(false)
|
||||||
val message = MutableLiveData<VkMessage?>()
|
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.VkGroup
|
||||||
import com.meloda.fast.api.model.VkMessage
|
import com.meloda.fast.api.model.VkMessage
|
||||||
import com.meloda.fast.api.model.VkUser
|
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.api.network.messages.*
|
||||||
import com.meloda.fast.base.viewmodel.BaseViewModel
|
import com.meloda.fast.base.viewmodel.BaseViewModel
|
||||||
import com.meloda.fast.base.viewmodel.VkEvent
|
import com.meloda.fast.base.viewmodel.VkEvent
|
||||||
@@ -173,6 +174,31 @@ class MessagesHistoryViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
}, onAnswer = { sendEvent(MessagesDelete(messagesIds = messagesIds ?: listOf())) })
|
}, 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(
|
data class MessagesLoaded(
|
||||||
@@ -198,3 +224,6 @@ data class MessagesDelete(
|
|||||||
val messagesIds: List<Int>
|
val messagesIds: List<Int>
|
||||||
) : VkEvent()
|
) : VkEvent()
|
||||||
|
|
||||||
|
data class MessagesEdit(
|
||||||
|
val message: VkMessage
|
||||||
|
) : VkEvent()
|
||||||
@@ -213,7 +213,7 @@ class MessagesPreparator constructor(
|
|||||||
} else {
|
} else {
|
||||||
text.isVisible = true
|
text.isVisible = true
|
||||||
bubble.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