Simple attachments in messages history (#164)
* new attachments in messages history - photo, video, audio, file, link * improve attachments in messages history and adjusted font size for logo's text in auth screen * audio duration, file preview and url preview are now visible in attachments in messages history screen * make MessageBubble width adapt to attachments container width * topbar back icon crossfade animation * implement rich text for message input * handle click and long click on attachments * added click and long click handlers for attachments in message bubbles * enabled opening photos, files, and links when clicked. * implemented basic long-click logging for photos. * handled back press to return to Conversations from other tabs. * corrected the logic for filtering and selecting video images. * updated string resources for attachments, including a new "Clip" string. * make MessageBubble mention text underline on out messages
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
package dev.meloda.fast.model
|
||||
|
||||
data class PhotoSize(
|
||||
val height: Int,
|
||||
val width: Int,
|
||||
val type: String,
|
||||
val url: String
|
||||
)
|
||||
@@ -6,8 +6,8 @@ enum class AttachmentType(var value: String) {
|
||||
UNKNOWN("unknown"),
|
||||
PHOTO("photo"),
|
||||
VIDEO("video"),
|
||||
AUDIO("audio"),
|
||||
FILE("doc"),
|
||||
AUDIO("audio"),
|
||||
LINK("link"),
|
||||
AUDIO_MESSAGE("audio_message"),
|
||||
MINI_APP("mini_app"),
|
||||
|
||||
@@ -27,7 +27,9 @@ data class VkFileData(
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Photo(val sizes: List<Size>) {
|
||||
data class Photo(
|
||||
val sizes: List<Size>
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Size(
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.meloda.fast.model.api.data
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import dev.meloda.fast.model.PhotoSize
|
||||
import dev.meloda.fast.model.api.domain.VkPhotoDomain
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@@ -35,7 +36,14 @@ data class VkPhotoData(
|
||||
ownerId = ownerId,
|
||||
hasTags = hasTags == true,
|
||||
accessKey = accessKey,
|
||||
sizes = sizes,
|
||||
sizes = sizes.map { size ->
|
||||
PhotoSize(
|
||||
height = size.height,
|
||||
width = size.width,
|
||||
type = size.type,
|
||||
url = size.url
|
||||
)
|
||||
},
|
||||
text = text,
|
||||
userId = userId
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ data class VkVideoData(
|
||||
@Json(name = "is_favorite") val isFavorite: Boolean?,
|
||||
@Json(name = "image") val image: List<Image>?,
|
||||
@Json(name = "first_frame") val firstFrame: List<FirstFrame>?,
|
||||
@Json(name = "files") val files: File?
|
||||
@Json(name = "files") val files: File?,
|
||||
) : VkAttachmentData {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
@@ -73,6 +73,7 @@ data class VkVideoData(
|
||||
accessKey = accessKey,
|
||||
title = title,
|
||||
views = views,
|
||||
duration = duration
|
||||
duration = duration,
|
||||
isShortVideo = type == "short_video"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ data class VkWallReplyData(
|
||||
val from_id: Long,
|
||||
val date: Int,
|
||||
val text: String,
|
||||
val post_id: Long,
|
||||
val owner_id: Long,
|
||||
val parents_stack: List<Int>,
|
||||
val likes: Likes,
|
||||
val post_id: Long?,
|
||||
val owner_id: Long?,
|
||||
val parents_stack: List<Int>?,
|
||||
val likes: Likes?,
|
||||
val reply_to_user: Int?,
|
||||
val reply_to_comment: Int?
|
||||
) {
|
||||
|
||||
@@ -3,6 +3,10 @@ package dev.meloda.fast.model.api.domain
|
||||
enum class FormatDataType {
|
||||
BOLD, ITALIC, UNDERLINE, URL;
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString().lowercase()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun parse(value: String): FormatDataType? =
|
||||
entries.firstOrNull { it.name.lowercase() == value }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.meloda.fast.model.api.domain
|
||||
|
||||
import dev.meloda.fast.model.PhotoSize
|
||||
import dev.meloda.fast.model.api.data.AttachmentType
|
||||
import dev.meloda.fast.model.api.data.VkPhotoData
|
||||
import java.util.Stack
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ data class VkPhotoDomain(
|
||||
val ownerId: Long,
|
||||
val hasTags: Boolean,
|
||||
val accessKey: String?,
|
||||
val sizes: List<VkPhotoData.Size>,
|
||||
val sizes: List<PhotoSize>,
|
||||
val text: String?,
|
||||
val userId: Long?
|
||||
) : VkAttachment {
|
||||
@@ -35,11 +35,15 @@ data class VkPhotoDomain(
|
||||
sizesChars.push(SIZE_TYPE_2560_2048)
|
||||
}
|
||||
|
||||
fun getMaxSize(): VkPhotoData.Size? {
|
||||
fun getMaxSize(): PhotoSize? {
|
||||
return getSizeOrSmaller(sizesChars.peek())
|
||||
}
|
||||
|
||||
fun getSizeOrNull(type: Char): VkPhotoData.Size? {
|
||||
fun getDefault(): PhotoSize? {
|
||||
return getSizeOrSmaller(SIZE_TYPE_1080_1024)
|
||||
}
|
||||
|
||||
fun getSizeOrNull(type: Char): PhotoSize? {
|
||||
for (size in sizes) {
|
||||
if (size.type == type.toString()) return size
|
||||
}
|
||||
@@ -47,7 +51,7 @@ data class VkPhotoDomain(
|
||||
return null
|
||||
}
|
||||
|
||||
fun getSizeOrSmaller(type: Char): VkPhotoData.Size? {
|
||||
fun getSizeOrSmaller(type: Char): PhotoSize? {
|
||||
val photoStack = sizesChars.clone() as Stack<*>
|
||||
|
||||
val sizeIndex = photoStack.search(type)
|
||||
|
||||
@@ -13,7 +13,8 @@ data class VkVideoDomain(
|
||||
val accessKey: String?,
|
||||
val title: String,
|
||||
val views: Int,
|
||||
val duration: Int
|
||||
val duration: Int,
|
||||
val isShortVideo: Boolean
|
||||
) : VkAttachment {
|
||||
|
||||
override val type: AttachmentType = AttachmentType.VIDEO
|
||||
@@ -22,6 +23,10 @@ data class VkVideoDomain(
|
||||
return images.find { it.width == width }
|
||||
}
|
||||
|
||||
fun getDefault(): VideoImage? {
|
||||
return imageForWidthAtLeast(720)
|
||||
}
|
||||
|
||||
fun imageForWidthAtLeast(width: Int): VideoImage? {
|
||||
var certainImages = images.sortedByDescending { it.width }
|
||||
var containsVertical = false
|
||||
@@ -36,9 +41,11 @@ data class VkVideoDomain(
|
||||
certainImages = certainImages.filter { it.shapeKind == ShapeKind.Vertical }
|
||||
}
|
||||
|
||||
certainImages = certainImages.filter { it.width >= width }
|
||||
val filteredCertainImages = certainImages.filter { it.width >= width }
|
||||
|
||||
return certainImages.firstOrNull()
|
||||
return filteredCertainImages
|
||||
.ifEmpty { certainImages }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.meloda.fast.model.api.requests
|
||||
|
||||
import dev.meloda.fast.model.api.asInt
|
||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
|
||||
data class MessagesGetHistoryRequest(
|
||||
val count: Int? = null,
|
||||
@@ -38,7 +39,8 @@ data class MessagesSendRequest(
|
||||
val disableMentions: Boolean? = null,
|
||||
val doNotParseLinks: Boolean? = null,
|
||||
val silent: Boolean? = null,
|
||||
val attachments: List<VkAttachment>? = null
|
||||
val attachments: List<VkAttachment>? = null,
|
||||
val formatData: VkMessage.FormatData? = null
|
||||
) {
|
||||
|
||||
val map: Map<String, String>
|
||||
@@ -54,6 +56,13 @@ data class MessagesSendRequest(
|
||||
disableMentions?.let { this["disable_mentions"] = it.asInt().toString() }
|
||||
doNotParseLinks?.let { this["dont_parse_links"] = it.asInt().toString() }
|
||||
silent?.let { this["silent"] = it.toString() }
|
||||
formatData?.let {
|
||||
this["format_data"] = "{\"version\":\"${formatData.version}\",\"items\":[" +
|
||||
formatData.items.joinToString(separator = ", ") { item ->
|
||||
"{\"type\":\"${item.type}\",\"offset\":${item.offset},\"length\":${item.length}}"
|
||||
} +
|
||||
"]}"
|
||||
}
|
||||
|
||||
// TODO: 05/05/2024, Danil Nikolaev: add attachments
|
||||
// attachments?.let {
|
||||
|
||||
Reference in New Issue
Block a user