From a3a282c32c8ee33f2a93103f823a302dbf2fb427 Mon Sep 17 00:00:00 2001 From: Danil Nikolaev Date: Tue, 14 Sep 2021 23:33:10 +0300 Subject: [PATCH] chat theme change event mark messages as important refactoring --- .../kotlin/com/meloda/fast/api/VkUtils.kt | 257 +++++++++++++++++- .../fast/api/datasource/MessagesDataSource.kt | 18 -- .../com/meloda/fast/api/model/VkMessage.kt | 9 +- .../api/model/attachments/VkAttachment.kt | 4 +- .../fast/api/model/attachments/VkAudio.kt | 3 + .../fast/api/model/attachments/VkCall.kt | 3 + .../fast/api/model/attachments/VkFile.kt | 3 + .../fast/api/model/attachments/VkGift.kt | 3 + .../fast/api/model/attachments/VkGraffiti.kt | 3 + .../fast/api/model/attachments/VkGroupCall.kt | 3 + .../fast/api/model/attachments/VkLink.kt | 3 + .../fast/api/model/attachments/VkMiniApp.kt | 3 + .../fast/api/model/attachments/VkPhoto.kt | 27 +- .../fast/api/model/attachments/VkPoll.kt | 3 + .../fast/api/model/attachments/VkSticker.kt | 3 + .../fast/api/model/attachments/VkVideo.kt | 3 + .../api/model/attachments/VkVoiceMessage.kt | 3 + .../fast/api/model/attachments/VkWall.kt | 3 + .../fast/api/model/attachments/VkWallReply.kt | 3 + .../fast/api/model/base/BaseVkMessage.kt | 3 +- .../api/model/base/attachments/BaseVkPhoto.kt | 19 +- .../{network => model}/request/AuthRequest.kt | 2 +- .../request/ConversationsRequest.kt | 2 +- .../request/MessagesRequest.kt | 17 +- .../request/UsersRequest.kt | 2 +- .../response/AuthResponse.kt | 2 +- .../response/ConversationsResponse.kt | 2 +- .../response/MessagesResponse.kt | 2 +- .../fast/api/model/response/UsersResponse.kt | 2 + .../com/meloda/fast/api/network/VKUrls.kt | 1 + .../datasource/AuthDataSource.kt | 4 +- .../datasource/ConversationsDataSource.kt | 4 +- .../network/datasource/MessagesDataSource.kt | 24 ++ .../datasource/UsersDataSource.kt | 4 +- .../meloda/fast/api/network/repo/AuthRepo.kt | 4 +- .../api/network/repo/ConversationsRepo.kt | 2 +- .../fast/api/network/repo/MessagesRepo.kt | 6 +- .../api/network/response/UsersResponse.kt | 5 - .../com/meloda/fast/database/AppDatabase.kt | 2 +- .../com/meloda/fast/di/NetworkModule.kt | 8 +- .../conversations/ConversationsFragment.kt | 51 ++-- .../conversations/ConversationsViewModel.kt | 8 +- .../fast/screens/login/LoginViewModel.kt | 4 +- .../messages/MessagesHistoryAdapter.kt | 122 ++++++++- .../messages/MessagesHistoryFragment.kt | 49 +++- .../messages/MessagesHistoryViewModel.kt | 39 ++- .../item_message_attachment_photo_in.xml | 19 ++ .../item_message_attachment_photo_out.xml | 20 ++ .../main/res/layout/item_message_service.xml | 10 +- app/src/main/res/navigation/nav_graph.xml | 9 + app/src/main/res/values-night/themes.xml | 17 +- app/src/main/res/values-v31/colors.xml | 1 + app/src/main/res/values/attrs.xml | 7 +- app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/themes.xml | 1 + 55 files changed, 722 insertions(+), 111 deletions(-) delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/datasource/MessagesDataSource.kt rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/request/AuthRequest.kt (97%) rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/request/ConversationsRequest.kt (94%) rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/request/MessagesRequest.kt (80%) rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/request/UsersRequest.kt (92%) rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/response/AuthResponse.kt (94%) rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/response/ConversationsResponse.kt (94%) rename app/src/main/kotlin/com/meloda/fast/api/{network => model}/response/MessagesResponse.kt (92%) create mode 100644 app/src/main/kotlin/com/meloda/fast/api/model/response/UsersResponse.kt rename app/src/main/kotlin/com/meloda/fast/api/{ => network}/datasource/AuthDataSource.kt (74%) rename app/src/main/kotlin/com/meloda/fast/api/{ => network}/datasource/ConversationsDataSource.kt (82%) create mode 100644 app/src/main/kotlin/com/meloda/fast/api/network/datasource/MessagesDataSource.kt rename app/src/main/kotlin/com/meloda/fast/api/{ => network}/datasource/UsersDataSource.kt (80%) delete mode 100644 app/src/main/kotlin/com/meloda/fast/api/network/response/UsersResponse.kt create mode 100644 app/src/main/res/layout/item_message_attachment_photo_in.xml create mode 100644 app/src/main/res/layout/item_message_attachment_photo_out.xml create mode 100644 app/src/main/res/navigation/nav_graph.xml diff --git a/app/src/main/kotlin/com/meloda/fast/api/VkUtils.kt b/app/src/main/kotlin/com/meloda/fast/api/VkUtils.kt index bfa61f8c..354dafdc 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/VkUtils.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/VkUtils.kt @@ -1,7 +1,10 @@ package com.meloda.fast.api import android.content.Context +import android.graphics.Typeface import android.graphics.drawable.Drawable +import android.text.SpannableString +import android.text.style.StyleSpan import androidx.core.content.ContextCompat import com.meloda.fast.R import com.meloda.fast.api.model.VkGroup @@ -51,9 +54,7 @@ object VkUtils { when (baseAttachment.getPreparedType()) { BaseVkAttachmentItem.AttachmentType.PHOTO -> { val photo = baseAttachment.photo ?: continue - attachments += VkPhoto( - link = photo.sizes[0].url - ) + attachments += photo.asVkPhoto() } BaseVkAttachmentItem.AttachmentType.VIDEO -> { val video = baseAttachment.video ?: continue @@ -206,8 +207,6 @@ object VkUtils { val actionUser = profiles?.get(memberId) val actionGroup = groups?.get(memberId) -// val actionUser = profiles?.find { it.id == memberId } -// val actionGroup = groups?.find { it.id == memberId } if (isUser && actionUser == null) return null if (isGroup && actionGroup == null) return null @@ -233,8 +232,6 @@ object VkUtils { val actionUser = profiles?.get(memberId) val actionGroup = groups?.get(memberId) -// val actionUser = profiles?.find { it.id == memberId } -// val actionGroup = groups?.find { it.id == memberId } if (isUser && actionUser == null) return null if (isGroup && actionGroup == null) return null @@ -302,11 +299,257 @@ object VkUtils { "$prefix took a screenshot" } + VkMessage.Action.CHAT_STYLE_UPDATE -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + "$prefix changed chat theme" + } null -> null else -> "[${message.action}]" } } + fun getActionMessageText( + message: VkMessage, + youPrefix: String, + profiles: HashMap? = null, + groups: HashMap? = null, + messageUser: VkUser? = null, + messageGroup: VkGroup? = null + ): SpannableString? { + return when (message.getPreparedAction()) { + VkMessage.Action.CHAT_CREATE -> { + val text = message.actionText ?: return null + + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix created «$text»" + + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + it.setSpan( + StyleSpan(Typeface.BOLD), + spanText.indexOf(text, startIndex = prefix.length), + text.length, 0 + ) + } + } + VkMessage.Action.CHAT_TITLE_UPDATE -> { + val text = message.actionText ?: return null + + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix renamed chat to «$text»" + + val startIndex = spanText.indexOf(text) + + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + it.setSpan( + StyleSpan(Typeface.BOLD), startIndex, startIndex + text.length, 0 + ) + } + } + VkMessage.Action.CHAT_PHOTO_UPDATE -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix updated the chat photo" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + VkMessage.Action.CHAT_PHOTO_REMOVE -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix deleted the chat photo" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + VkMessage.Action.CHAT_KICK_USER -> { + val memberId = message.actionMemberId ?: return null + val isUser = memberId > 0 + val isGroup = memberId < 0 + + val actionUser = profiles?.get(memberId) + val actionGroup = groups?.get(memberId) + + if (isUser && actionUser == null) return null + if (isGroup && actionGroup == null) return null + + if (memberId == message.fromId) { + val prefix = if (memberId == UserConfig.userId) youPrefix + else actionUser.toString() + val spanText = "$prefix left the chat" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } else { + val prefix = + if (message.fromId == UserConfig.userId) youPrefix + else messageUser?.toString() ?: messageGroup?.toString() ?: "..." + val postfix = + if (memberId == UserConfig.userId) youPrefix.lowercase() + else actionUser.toString() + + val spanText = "$prefix kicked $postfix" + val startIndex = spanText.indexOf(postfix) + + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + it.setSpan( + StyleSpan(Typeface.BOLD), startIndex, startIndex + postfix.length, 0 + ) + } + } + } + VkMessage.Action.CHAT_INVITE_USER -> { + val memberId = message.actionMemberId ?: 0 + val isUser = memberId > 0 + val isGroup = memberId < 0 + + val actionUser = profiles?.get(memberId) + val actionGroup = groups?.get(memberId) + + if (isUser && actionUser == null) return null + if (isGroup && actionGroup == null) return null + + if (memberId == message.fromId) { + val prefix = if (memberId == UserConfig.userId) youPrefix + else actionUser.toString() + val spanText = "$prefix returned the chat" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } else { + val prefix = if (message.fromId == UserConfig.userId) youPrefix + else messageUser?.toString() ?: messageGroup?.toString() ?: "..." + val postfix = + if (memberId == UserConfig.userId) youPrefix.lowercase() + else actionUser.toString() + + val spanText = "$prefix invited $postfix" + val startIndex = spanText.indexOf(postfix) + + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + it.setSpan( + StyleSpan(Typeface.BOLD), startIndex, startIndex + postfix.length, 0 + ) + } + } + } + VkMessage.Action.CHAT_INVITE_USER_BY_LINK -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix joined the chat via link" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + VkMessage.Action.CHAT_INVITE_USER_BY_CALL_LINK -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix joined the call via link" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + VkMessage.Action.CHAT_PIN_MESSAGE -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val actionMessage = message.actionMessage ?: return null + + val spanText = "$prefix pinned message «$actionMessage»" + val startIndex = spanText.indexOf(actionMessage) + + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + it.setSpan( + StyleSpan(Typeface.BOLD), startIndex, startIndex + actionMessage.length, 0 + ) + } + } + VkMessage.Action.CHAT_UNPIN_MESSAGE -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix unpinned message" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + VkMessage.Action.CHAT_SCREENSHOT -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isGroup() -> messageGroup?.name + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix took a screenshot" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + VkMessage.Action.CHAT_STYLE_UPDATE -> { + val prefix = when { + message.fromId == UserConfig.userId -> youPrefix + message.isUser() -> messageUser?.toString() + else -> return null + } ?: return null + + val spanText = "$prefix changed chat theme" + SpannableString(spanText).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, prefix.length, 0) + } + } + null -> null + else -> SpannableString("[${message.action}]") + } + } + fun getForwardsConversationText(context: Context, message: VkMessage): String? { if (message.forwards.isNullOrEmpty()) return null diff --git a/app/src/main/kotlin/com/meloda/fast/api/datasource/MessagesDataSource.kt b/app/src/main/kotlin/com/meloda/fast/api/datasource/MessagesDataSource.kt deleted file mode 100644 index 6e2fc477..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/datasource/MessagesDataSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.meloda.fast.api.datasource - -import com.meloda.fast.api.network.repo.MessagesRepo -import com.meloda.fast.api.network.request.MessagesGetHistoryRequest -import com.meloda.fast.api.network.request.MessagesSendRequest -import com.meloda.fast.database.dao.MessagesDao -import javax.inject.Inject - -class MessagesDataSource @Inject constructor( - private val repo: MessagesRepo, - private val dao: MessagesDao -) { - - suspend fun getHistory(params: MessagesGetHistoryRequest) = repo.getHistory(params.map) - - suspend fun send(params: MessagesSendRequest) = repo.send(params.map) - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/VkMessage.kt b/app/src/main/kotlin/com/meloda/fast/api/model/VkMessage.kt index 58f45998..fca84ab3 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/VkMessage.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/VkMessage.kt @@ -24,7 +24,8 @@ data class VkMessage( val actionText: String? = null, val actionConversationMessageId: Int? = null, val actionMessage: String? = null, - val geoType: String? = null + val geoType: String? = null, + val important: Boolean = false ) : Parcelable { @IgnoredOnParcel @@ -61,7 +62,8 @@ data class VkMessage( actionText = actionText, actionConversationMessageId = actionConversationMessageId, actionMessage = actionMessage, - geoType = geoType + geoType = geoType, + important = important ) enum class Action(val value: String) { @@ -78,7 +80,8 @@ data class VkMessage( // TODO: 9/11/2021 catch this shit CHAT_INVITE_USER_BY_CALL("chat_invite_user_by_call"), - CHAT_INVITE_USER_BY_CALL_LINK("chat_invite_user_by_call_join_link"); + CHAT_INVITE_USER_BY_CALL_LINK("chat_invite_user_by_call_join_link"), + CHAT_STYLE_UPDATE("conversation_style_update"); companion object { fun parse(value: String) = values().first { it.value == value } diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAttachment.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAttachment.kt index 5c6ce70c..61b6547d 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAttachment.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAttachment.kt @@ -1,3 +1,5 @@ package com.meloda.fast.api.model.attachments -abstract class VkAttachment \ No newline at end of file +import android.os.Parcelable + +abstract class VkAttachment : Parcelable \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAudio.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAudio.kt index 5a5ec10a..cd6870d4 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAudio.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkAudio.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkAudio( val link: String ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkCall.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkCall.kt index 5c418b22..d8ef9773 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkCall.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkCall.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkCall( val initiatorId: Int ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkFile.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkFile.kt index e8eaaa23..b5ba69d4 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkFile.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkFile.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkFile( val link: String ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGift.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGift.kt index 75f08967..30f1aeb4 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGift.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGift.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkGift( val link: String ) : VkAttachment() diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGraffiti.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGraffiti.kt index 7f7ddebc..4c71c0b6 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGraffiti.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGraffiti.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkGraffiti( val link: String ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGroupCall.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGroupCall.kt index f23d0194..32bfbd43 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGroupCall.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkGroupCall.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkGroupCall( val initiatorId: Int ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkLink.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkLink.kt index 6e68af59..1d9142cc 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkLink.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkLink.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkLink( val link: String ) : VkAttachment() diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkMiniApp.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkMiniApp.kt index 781ba12e..499517cb 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkMiniApp.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkMiniApp.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkMiniApp( val link: String ) : VkAttachment() diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPhoto.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPhoto.kt index 2e1579ba..e5fdc2ea 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPhoto.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPhoto.kt @@ -1,5 +1,28 @@ package com.meloda.fast.api.model.attachments +import com.meloda.fast.api.model.base.attachments.Size +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkPhoto( - val link: String -) : VkAttachment() \ No newline at end of file + val albumId: Int, + val date: Int, + val id: Int, + val ownerId: Int, + val hasTags: Boolean, + val accessKey: String?, + val sizes: List, + val text: String, + val userId: Int? +) : VkAttachment() { + + fun sizeOfType(type: Char): Size? { + for (size in sizes) { + if (size.type == type.toString()) + return size + } + + return null + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPoll.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPoll.kt index ec8742a0..2220f146 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPoll.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkPoll.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkPoll( val id: Int ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkSticker.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkSticker.kt index 43aeefdc..bc855ba2 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkSticker.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkSticker.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkSticker( val link: String ) : VkAttachment() diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVideo.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVideo.kt index 77c0d427..874f7b3d 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVideo.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVideo.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkVideo( val link: String ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVoiceMessage.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVoiceMessage.kt index e701a35f..c239755c 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVoiceMessage.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkVoiceMessage.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkVoiceMessage( val link: String ) : VkAttachment() diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWall.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWall.kt index e2f54efe..63336f53 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWall.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWall.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkWall( val id: Int ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWallReply.kt b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWallReply.kt index 6930c369..24620076 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWallReply.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/attachments/VkWallReply.kt @@ -1,5 +1,8 @@ package com.meloda.fast.api.model.attachments +import kotlinx.parcelize.Parcelize + +@Parcelize data class VkWallReply( val id: Int ) : VkAttachment() \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/base/BaseVkMessage.kt b/app/src/main/kotlin/com/meloda/fast/api/model/base/BaseVkMessage.kt index 8a816ad2..e03a9bdf 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/base/BaseVkMessage.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/base/BaseVkMessage.kt @@ -46,7 +46,8 @@ data class BaseVkMessage( actionText = action?.text, actionConversationMessageId = action?.conversationMessageId, actionMessage = action?.message, - geoType = geo?.type + geoType = geo?.type, + important = important ).also { it.attachments = VkUtils.parseAttachments(attachments) it.forwards = VkUtils.parseForwards(fwdMessages) diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/base/attachments/BaseVkPhoto.kt b/app/src/main/kotlin/com/meloda/fast/api/model/base/attachments/BaseVkPhoto.kt index 9cb21093..6e89e263 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/model/base/attachments/BaseVkPhoto.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/base/attachments/BaseVkPhoto.kt @@ -2,6 +2,7 @@ package com.meloda.fast.api.model.base.attachments import android.os.Parcelable import com.google.gson.annotations.SerializedName +import com.meloda.fast.api.model.attachments.VkPhoto import kotlinx.parcelize.Parcelize @Parcelize @@ -15,12 +16,26 @@ data class BaseVkPhoto( @SerializedName("has_tags") val hasTags: Boolean, @SerializedName("access_key") - val accessKey: String, + val accessKey: String?, val sizes: List, val text: String, @SerializedName("user_id") val userId: Int? -) : BaseVkAttachment() +) : BaseVkAttachment() { + + fun asVkPhoto() = VkPhoto( + albumId = albumId, + date = date, + id = id, + ownerId = ownerId, + hasTags = hasTags, + accessKey = accessKey, + sizes = sizes, + text = text, + userId = userId + ) + +} @Parcelize data class Size( diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/request/AuthRequest.kt b/app/src/main/kotlin/com/meloda/fast/api/model/request/AuthRequest.kt similarity index 97% rename from app/src/main/kotlin/com/meloda/fast/api/network/request/AuthRequest.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/request/AuthRequest.kt index 8e53e40a..6868f545 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/request/AuthRequest.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/request/AuthRequest.kt @@ -1,4 +1,4 @@ -package com.meloda.fast.api.network.request +package com.meloda.fast.api.model.request import android.os.Parcelable import com.google.gson.annotations.SerializedName diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/request/ConversationsRequest.kt b/app/src/main/kotlin/com/meloda/fast/api/model/request/ConversationsRequest.kt similarity index 94% rename from app/src/main/kotlin/com/meloda/fast/api/network/request/ConversationsRequest.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/request/ConversationsRequest.kt index ce6b6cea..d5a1e66e 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/request/ConversationsRequest.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/request/ConversationsRequest.kt @@ -1,4 +1,4 @@ -package com.meloda.fast.api.network.request +package com.meloda.fast.api.model.request import android.os.Parcelable import kotlinx.parcelize.Parcelize diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/request/MessagesRequest.kt b/app/src/main/kotlin/com/meloda/fast/api/model/request/MessagesRequest.kt similarity index 80% rename from app/src/main/kotlin/com/meloda/fast/api/network/request/MessagesRequest.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/request/MessagesRequest.kt index 5e7f0096..3bc740b1 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/request/MessagesRequest.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/request/MessagesRequest.kt @@ -1,6 +1,7 @@ -package com.meloda.fast.api.network.request +package com.meloda.fast.api.model.request import android.os.Parcelable +import com.google.gson.annotations.SerializedName import kotlinx.parcelize.Parcelize @Parcelize @@ -54,5 +55,19 @@ data class MessagesSendRequest( disableMentions?.let { this["disable_mentions"] = (if (it) 1 else 0).toString() } dontParseLinks?.let { this["dont_parse_links"] = (if (it) 1 else 0).toString() } } +} + +@Parcelize +data class MessagesMarkAsImportantRequest( + @SerializedName("message_ids") + val messagesIds: List, + val important: Boolean +) : Parcelable { + + val map + get() = mutableMapOf( + "message_ids" to messagesIds.joinToString { it.toString() }, + "important" to (if (important) 1 else 0).toString() + ) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/request/UsersRequest.kt b/app/src/main/kotlin/com/meloda/fast/api/model/request/UsersRequest.kt similarity index 92% rename from app/src/main/kotlin/com/meloda/fast/api/network/request/UsersRequest.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/request/UsersRequest.kt index 053fc785..afb9b2ab 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/request/UsersRequest.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/request/UsersRequest.kt @@ -1,4 +1,4 @@ -package com.meloda.fast.api.network.request +package com.meloda.fast.api.model.request import android.os.Parcelable import kotlinx.parcelize.Parcelize diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/response/AuthResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/model/response/AuthResponse.kt similarity index 94% rename from app/src/main/kotlin/com/meloda/fast/api/network/response/AuthResponse.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/response/AuthResponse.kt index e9fe49b3..23e6c81f 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/response/AuthResponse.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/response/AuthResponse.kt @@ -1,4 +1,4 @@ -package com.meloda.fast.api.network.response +package com.meloda.fast.api.model.response import android.os.Parcelable import com.google.gson.annotations.SerializedName diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/model/response/ConversationsResponse.kt similarity index 94% rename from app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/response/ConversationsResponse.kt index 951e5b55..e3e1a821 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/response/ConversationsResponse.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/response/ConversationsResponse.kt @@ -1,4 +1,4 @@ -package com.meloda.fast.api.network.response +package com.meloda.fast.api.model.response import android.os.Parcelable import com.google.gson.annotations.SerializedName diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/model/response/MessagesResponse.kt similarity index 92% rename from app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt rename to app/src/main/kotlin/com/meloda/fast/api/model/response/MessagesResponse.kt index bec4576f..9ddeeb24 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/response/MessagesResponse.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/model/response/MessagesResponse.kt @@ -1,4 +1,4 @@ -package com.meloda.fast.api.network.response +package com.meloda.fast.api.model.response import android.os.Parcelable import com.meloda.fast.api.model.base.BaseVkConversation diff --git a/app/src/main/kotlin/com/meloda/fast/api/model/response/UsersResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/model/response/UsersResponse.kt new file mode 100644 index 00000000..dede65e8 --- /dev/null +++ b/app/src/main/kotlin/com/meloda/fast/api/model/response/UsersResponse.kt @@ -0,0 +1,2 @@ +package com.meloda.fast.api.model.response + diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/VKUrls.kt b/app/src/main/kotlin/com/meloda/fast/api/network/VKUrls.kt index 7395f62f..cde80070 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/VKUrls.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/VKUrls.kt @@ -21,6 +21,7 @@ object VKUrls { object Messages { const val GetHistory = "$API/messages.getHistory" const val Send = "$API/messages.send" + const val MarkAsImportant = "$API/messages.markAsImportant" } diff --git a/app/src/main/kotlin/com/meloda/fast/api/datasource/AuthDataSource.kt b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/AuthDataSource.kt similarity index 74% rename from app/src/main/kotlin/com/meloda/fast/api/datasource/AuthDataSource.kt rename to app/src/main/kotlin/com/meloda/fast/api/network/datasource/AuthDataSource.kt index 449f62c9..0a1f63b6 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/datasource/AuthDataSource.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/AuthDataSource.kt @@ -1,7 +1,7 @@ -package com.meloda.fast.api.datasource +package com.meloda.fast.api.network.datasource import com.meloda.fast.api.network.repo.AuthRepo -import com.meloda.fast.api.network.request.RequestAuthDirect +import com.meloda.fast.api.model.request.RequestAuthDirect import javax.inject.Inject class AuthDataSource @Inject constructor( diff --git a/app/src/main/kotlin/com/meloda/fast/api/datasource/ConversationsDataSource.kt b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/ConversationsDataSource.kt similarity index 82% rename from app/src/main/kotlin/com/meloda/fast/api/datasource/ConversationsDataSource.kt rename to app/src/main/kotlin/com/meloda/fast/api/network/datasource/ConversationsDataSource.kt index 1b78db0e..198bf9b3 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/datasource/ConversationsDataSource.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/ConversationsDataSource.kt @@ -1,8 +1,8 @@ -package com.meloda.fast.api.datasource +package com.meloda.fast.api.network.datasource import com.meloda.fast.api.model.VkConversation import com.meloda.fast.api.network.repo.ConversationsRepo -import com.meloda.fast.api.network.request.ConversationsGetRequest +import com.meloda.fast.api.model.request.ConversationsGetRequest import com.meloda.fast.database.dao.ConversationsDao import javax.inject.Inject diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/datasource/MessagesDataSource.kt b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/MessagesDataSource.kt new file mode 100644 index 00000000..4f19fc53 --- /dev/null +++ b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/MessagesDataSource.kt @@ -0,0 +1,24 @@ +package com.meloda.fast.api.network.datasource + +import com.meloda.fast.api.model.request.MessagesGetHistoryRequest +import com.meloda.fast.api.model.request.MessagesMarkAsImportantRequest +import com.meloda.fast.api.model.request.MessagesSendRequest +import com.meloda.fast.api.network.repo.MessagesRepo +import com.meloda.fast.database.dao.MessagesDao +import javax.inject.Inject + +class MessagesDataSource @Inject constructor( + private val repo: MessagesRepo, + private val dao: MessagesDao +) { + + suspend fun getHistory(params: MessagesGetHistoryRequest) = + repo.getHistory(params.map) + + suspend fun send(params: MessagesSendRequest) = + repo.send(params.map) + + suspend fun markAsImportant(params: MessagesMarkAsImportantRequest) = + repo.markAsImportant(params.map) + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/datasource/UsersDataSource.kt b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/UsersDataSource.kt similarity index 80% rename from app/src/main/kotlin/com/meloda/fast/api/datasource/UsersDataSource.kt rename to app/src/main/kotlin/com/meloda/fast/api/network/datasource/UsersDataSource.kt index 1cc54c68..7e9939cf 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/datasource/UsersDataSource.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/datasource/UsersDataSource.kt @@ -1,8 +1,8 @@ -package com.meloda.fast.api.datasource +package com.meloda.fast.api.network.datasource import com.meloda.fast.api.model.VkUser import com.meloda.fast.api.network.repo.UsersRepo -import com.meloda.fast.api.network.request.UsersGetRequest +import com.meloda.fast.api.model.request.UsersGetRequest import com.meloda.fast.database.dao.UsersDao import javax.inject.Inject diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/repo/AuthRepo.kt b/app/src/main/kotlin/com/meloda/fast/api/network/repo/AuthRepo.kt index 39fde13a..60fed0f8 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/repo/AuthRepo.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/repo/AuthRepo.kt @@ -1,9 +1,9 @@ package com.meloda.fast.api.network.repo import com.meloda.fast.api.network.VKUrls -import com.meloda.fast.api.network.response.ResponseAuthDirect +import com.meloda.fast.api.model.response.ResponseAuthDirect import com.meloda.fast.api.network.Answer -import com.meloda.fast.api.network.response.ResponseSendSms +import com.meloda.fast.api.model.response.ResponseSendSms import retrofit2.http.* interface AuthRepo { diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/repo/ConversationsRepo.kt b/app/src/main/kotlin/com/meloda/fast/api/network/repo/ConversationsRepo.kt index 54e988af..9f0c8d4c 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/repo/ConversationsRepo.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/repo/ConversationsRepo.kt @@ -3,7 +3,7 @@ package com.meloda.fast.api.network.repo import com.meloda.fast.api.base.ApiResponse import com.meloda.fast.api.network.Answer import com.meloda.fast.api.network.VKUrls -import com.meloda.fast.api.network.response.ConversationsGetResponse +import com.meloda.fast.api.model.response.ConversationsGetResponse import retrofit2.http.FieldMap import retrofit2.http.FormUrlEncoded import retrofit2.http.POST diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/repo/MessagesRepo.kt b/app/src/main/kotlin/com/meloda/fast/api/network/repo/MessagesRepo.kt index 084796e3..1476113a 100644 --- a/app/src/main/kotlin/com/meloda/fast/api/network/repo/MessagesRepo.kt +++ b/app/src/main/kotlin/com/meloda/fast/api/network/repo/MessagesRepo.kt @@ -1,9 +1,9 @@ package com.meloda.fast.api.network.repo import com.meloda.fast.api.base.ApiResponse +import com.meloda.fast.api.model.response.MessagesGetHistoryResponse import com.meloda.fast.api.network.Answer import com.meloda.fast.api.network.VKUrls -import com.meloda.fast.api.network.response.MessagesGetHistoryResponse import retrofit2.http.FieldMap import retrofit2.http.FormUrlEncoded import retrofit2.http.POST @@ -18,4 +18,8 @@ interface MessagesRepo { @POST(VKUrls.Messages.Send) suspend fun send(@FieldMap params: Map): Answer> + @FormUrlEncoded + @POST(VKUrls.Messages.MarkAsImportant) + suspend fun markAsImportant(@FieldMap params: Map): Answer>> + } \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/api/network/response/UsersResponse.kt b/app/src/main/kotlin/com/meloda/fast/api/network/response/UsersResponse.kt deleted file mode 100644 index 4dc28b7e..00000000 --- a/app/src/main/kotlin/com/meloda/fast/api/network/response/UsersResponse.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.meloda.fast.api.network.response - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - diff --git a/app/src/main/kotlin/com/meloda/fast/database/AppDatabase.kt b/app/src/main/kotlin/com/meloda/fast/database/AppDatabase.kt index 00967ddd..fdb4ddd3 100644 --- a/app/src/main/kotlin/com/meloda/fast/database/AppDatabase.kt +++ b/app/src/main/kotlin/com/meloda/fast/database/AppDatabase.kt @@ -18,7 +18,7 @@ import com.meloda.fast.database.dao.UsersDao VkUser::class, VkGroup::class ], - version = 15, + version = 16, exportSchema = false ) abstract class AppDatabase : RoomDatabase() { diff --git a/app/src/main/kotlin/com/meloda/fast/di/NetworkModule.kt b/app/src/main/kotlin/com/meloda/fast/di/NetworkModule.kt index cb6a23ee..4825ad45 100644 --- a/app/src/main/kotlin/com/meloda/fast/di/NetworkModule.kt +++ b/app/src/main/kotlin/com/meloda/fast/di/NetworkModule.kt @@ -2,10 +2,10 @@ package com.meloda.fast.di import com.google.gson.Gson import com.google.gson.GsonBuilder -import com.meloda.fast.api.datasource.AuthDataSource -import com.meloda.fast.api.datasource.ConversationsDataSource -import com.meloda.fast.api.datasource.MessagesDataSource -import com.meloda.fast.api.datasource.UsersDataSource +import com.meloda.fast.api.network.datasource.AuthDataSource +import com.meloda.fast.api.network.datasource.ConversationsDataSource +import com.meloda.fast.api.network.datasource.MessagesDataSource +import com.meloda.fast.api.network.datasource.UsersDataSource import com.meloda.fast.api.network.AuthInterceptor import com.meloda.fast.api.network.ResultCallFactory import com.meloda.fast.api.network.repo.AuthRepo diff --git a/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsFragment.kt b/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsFragment.kt index a7c4192f..df309ada 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsFragment.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsFragment.kt @@ -9,7 +9,6 @@ import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import coil.load import com.google.android.material.appbar.AppBarLayout -import com.google.android.material.snackbar.Snackbar import com.meloda.fast.R import com.meloda.fast.api.UserConfig import com.meloda.fast.api.model.VkConversation @@ -27,34 +26,38 @@ class ConversationsFragment : BaseViewModelFragment(R.layout.fragment_conversations) { companion object { - val TAG: String = ConversationsFragment::class.java.name + const val TAG = "ConversationsFragment" } override val viewModel: ConversationsViewModel by viewModels() private val binding: FragmentConversationsBinding by viewBinding() - private lateinit var adapter: ConversationsAdapter - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewModel.loadProfileUser() - - prepareViews() - - adapter = ConversationsAdapter(requireContext(), mutableListOf()).also { + private val adapter: ConversationsAdapter by lazy { + ConversationsAdapter( + requireContext(), + mutableListOf(), + hashMapOf(), + hashMapOf() + ).also { it.itemClickListener = this::onItemClick it.itemLongClickListener = this::onItemLongClick } + } + + private var isPaused = false + + override fun onPause() { + super.onPause() + isPaused = true + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + prepareViews() + binding.recyclerView.adapter = adapter - viewModel.loadConversations() - - binding.createChat.setOnClickListener { - Snackbar.make(it, "Test Snackbar with action", Snackbar.LENGTH_LONG) - .setAction("Action") {}.show() - - } + binding.createChat.setOnClickListener {} UserConfig.vkUser.observe(viewLifecycleOwner) { it?.let { user -> binding.avatar.load(user.photo200) { crossfade(100) } } @@ -68,10 +71,16 @@ class ConversationsFragment : val alpha = 1 - abs(verticalOffset * 0.01).toFloat() -// println("offset: $verticalOffset; alpha: $alpha") - binding.avatarContainer.alpha = alpha }) + + if (isPaused) { + isPaused = false + return + } + + viewModel.loadProfileUser() + viewModel.loadConversations() } override fun onEvent(event: VKEvent) { diff --git a/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsViewModel.kt b/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsViewModel.kt index 66b74857..d4d9209b 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsViewModel.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/conversations/ConversationsViewModel.kt @@ -3,13 +3,13 @@ package com.meloda.fast.screens.conversations import androidx.lifecycle.viewModelScope import com.meloda.fast.api.UserConfig import com.meloda.fast.api.VKConstants -import com.meloda.fast.api.datasource.ConversationsDataSource -import com.meloda.fast.api.datasource.UsersDataSource +import com.meloda.fast.api.network.datasource.ConversationsDataSource +import com.meloda.fast.api.network.datasource.UsersDataSource import com.meloda.fast.api.model.VkConversation import com.meloda.fast.api.model.VkGroup import com.meloda.fast.api.model.VkUser -import com.meloda.fast.api.network.request.ConversationsGetRequest -import com.meloda.fast.api.network.request.UsersGetRequest +import com.meloda.fast.api.model.request.ConversationsGetRequest +import com.meloda.fast.api.model.request.UsersGetRequest import com.meloda.fast.base.viewmodel.BaseViewModel import com.meloda.fast.base.viewmodel.StartProgressEvent import com.meloda.fast.base.viewmodel.StopProgressEvent diff --git a/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt b/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt index cc443ec5..ffed3866 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/login/LoginViewModel.kt @@ -6,8 +6,8 @@ import com.meloda.fast.api.UserConfig import com.meloda.fast.api.VKConstants import com.meloda.fast.api.VKException import com.meloda.fast.api.VkUtils -import com.meloda.fast.api.datasource.AuthDataSource -import com.meloda.fast.api.network.request.RequestAuthDirect +import com.meloda.fast.api.network.datasource.AuthDataSource +import com.meloda.fast.api.model.request.RequestAuthDirect import com.meloda.fast.base.viewmodel.BaseViewModel import com.meloda.fast.base.viewmodel.StartProgressEvent import com.meloda.fast.base.viewmodel.StopProgressEvent diff --git a/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryAdapter.kt b/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryAdapter.kt index 44342538..542d31dc 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryAdapter.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryAdapter.kt @@ -3,19 +3,22 @@ package com.meloda.fast.screens.messages import android.content.Context import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.appcompat.widget.LinearLayoutCompat import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import coil.load +import com.meloda.fast.R +import com.meloda.fast.api.VkUtils 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.VkPhoto import com.meloda.fast.base.adapter.BaseAdapter import com.meloda.fast.base.adapter.BaseHolder import com.meloda.fast.common.AppGlobal -import com.meloda.fast.databinding.ItemMessageInBinding -import com.meloda.fast.databinding.ItemMessageOutBinding -import com.meloda.fast.databinding.ItemMessageServiceBinding +import com.meloda.fast.databinding.* import com.meloda.fast.util.AndroidUtils import kotlin.math.roundToInt @@ -37,6 +40,15 @@ class MessagesHistoryAdapter constructor( if (viewType == -1) { getItem(position).let { if (it.action != null) viewType = SERVICE + + val attachments = it.attachments ?: return@let + if (attachments.isEmpty()) return@let + if (VkUtils.isAttachmentsHaveOneType(attachments) && + attachments[0] is VkPhoto + ) { + return if (it.isOut) ATTACHMENT_PHOTOS_OUT else ATTACHMENT_PHOTOS_IN + } + if (it.isOut) viewType = OUTGOING if (!it.isOut) viewType = INCOMING } @@ -52,9 +64,21 @@ class MessagesHistoryAdapter constructor( return when (viewType) { HEADER -> Header(createEmptyView(60)) FOOTER -> Footer(createEmptyView(36)) - SERVICE -> ServiceMessage(ItemMessageServiceBinding.inflate(inflater, parent, false)) - OUTGOING -> OutgoingMessage(ItemMessageOutBinding.inflate(inflater, parent, false)) - INCOMING -> IncomingMessage(ItemMessageInBinding.inflate(inflater, parent, false)) + SERVICE -> ServiceMessage( + ItemMessageServiceBinding.inflate(inflater, parent, false) + ) + ATTACHMENT_PHOTOS_IN -> AttachmentPhotosIncoming( + ItemMessageAttachmentPhotoInBinding.inflate(inflater, parent, false) + ) + ATTACHMENT_PHOTOS_OUT -> AttachmentPhotosOutgoing( + ItemMessageAttachmentPhotoOutBinding.inflate(inflater, parent, false) + ) + OUTGOING -> OutgoingMessage( + ItemMessageOutBinding.inflate(inflater, parent, false) + ) + INCOMING -> IncomingMessage( + ItemMessageInBinding.inflate(inflater, parent, false) + ) else -> Holder() } } @@ -83,12 +107,87 @@ class MessagesHistoryAdapter constructor( inner class Footer(v: View) : Holder(v) + inner class AttachmentPhotosIncoming( + private val binding: ItemMessageAttachmentPhotoInBinding + ) : Holder(binding.root) { + + init { + binding.photo.shapeAppearanceModel = binding.photo.shapeAppearanceModel.withCornerSize { + AndroidUtils.px(12) + } + } + + override fun bind(position: Int) { + val message = getItem(position) + + val photo = message.attachments?.get(0) as? VkPhoto ?: return + + val size = photo.sizeOfType('m') ?: return + + binding.photo.layoutParams = FrameLayout.LayoutParams( + AndroidUtils.px(size.width).roundToInt(), + AndroidUtils.px(size.height).roundToInt() + ) + + binding.photo.load(size.url) + } + + } + + inner class AttachmentPhotosOutgoing( + private val binding: ItemMessageAttachmentPhotoOutBinding + ) : Holder(binding.root) { + + init { + binding.photo.shapeAppearanceModel = binding.photo.shapeAppearanceModel.withCornerSize { + AndroidUtils.px(12) + } + } + + override fun bind(position: Int) { + val message = getItem(position) + + val photo = message.attachments?.get(0) as? VkPhoto ?: return + + val size = photo.sizeOfType('m') ?: return + + binding.photo.layoutParams = LinearLayoutCompat.LayoutParams( + AndroidUtils.px(size.width).roundToInt(), + AndroidUtils.px(size.height).roundToInt() + ) + + binding.photo.load(size.url) + } + + } + inner class ServiceMessage( private val binding: ItemMessageServiceBinding ) : Holder(binding.root) { - override fun bind(position: Int) { + private val youPrefix = context.getString(R.string.you_message_prefix) + override fun bind(position: Int) { + val message = getItem(position) + + val messageUser = + if (message.isUser()) profiles[message.fromId] + else null + + val messageGroup = + if (message.isGroup()) groups[message.fromId] + else null + + message.action ?: return + + binding.message.text = VkUtils.getActionMessageText( + message = message, + youPrefix = youPrefix, + profiles = profiles, + groups = groups, + messageUser = messageUser, + messageGroup = messageGroup + ) } } @@ -176,11 +275,14 @@ class MessagesHistoryAdapter constructor( } companion object { - private const val INCOMING = 1001 - private const val OUTGOING = 1002 - private const val SERVICE = 1003 + private const val SERVICE = 1 private const val HEADER = 0 private const val FOOTER = 2 + private const val INCOMING = 3 + private const val OUTGOING = 4 + + private const val ATTACHMENT_PHOTOS_IN = 101 + private const val ATTACHMENT_PHOTOS_OUT = 1011 private val COMPARATOR = object : DiffUtil.ItemCallback() { override fun areItemsTheSame( diff --git a/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryFragment.kt b/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryFragment.kt index 5fb96ea0..679578a4 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryFragment.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryFragment.kt @@ -12,6 +12,7 @@ import androidx.lifecycle.MutableLiveData import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import coil.load +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.meloda.fast.R import com.meloda.fast.api.UserConfig import com.meloda.fast.api.model.VkConversation @@ -57,7 +58,10 @@ class MessagesHistoryFragment : } private val adapter: MessagesHistoryAdapter by lazy { - MessagesHistoryAdapter(requireContext(), mutableListOf(), conversation) + MessagesHistoryAdapter(requireContext(), mutableListOf(), conversation).also { + it.itemClickListener = this::onItemClick + it.itemLongClickListener = this::onItemLongClick + } } private var timestampTimer: Timer? = null @@ -183,6 +187,7 @@ class MessagesHistoryFragment : } } + private fun performAction() { if (action.value == Action.RECORD) { @@ -203,7 +208,7 @@ class MessagesHistoryFragment : ) adapter.add(message) - adapter.notifyItemRangeInserted(adapter.lastPosition - 1, 1) + adapter.notifyDataSetChanged() binding.recyclerView.smoothScrollToPosition(adapter.lastPosition) binding.message.clear() @@ -217,6 +222,7 @@ class MessagesHistoryFragment : override fun onEvent(event: VKEvent) { when (event) { + is MessagesMarkAsImportant -> markMessagesAsImportant(event) is MessagesLoaded -> refreshMessages(event) is StartProgressEvent -> onProgressStarted() is StopProgressEvent -> onProgressStopped() @@ -264,6 +270,19 @@ class MessagesHistoryFragment : } } + private fun markMessagesAsImportant(event: MessagesMarkAsImportant) { + var changed = false + for (i in adapter.values.indices) { + val message = adapter.values[i] + if (event.messagesIds.contains(message.id)) { + if (!changed) changed = true + adapter.values[i] = message.copy(important = event.important) + } + } + + if (changed) adapter.notifyDataSetChanged() + } + private fun refreshMessages(event: MessagesLoaded) { adapter.profiles += event.profiles adapter.groups += event.groups @@ -282,4 +301,30 @@ class MessagesHistoryFragment : else binding.recyclerView.scrollToPosition(adapter.lastPosition) } + private fun onItemClick(position: Int) { + val message = adapter.values[position] + + val important = if (message.important) "Unmark as important" else "Mark as important" + + val params = arrayOf(important) + + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setItems(params) { _, which -> + if (which == 0) { + viewModel.markAsImportant( + messagesIds = listOf(message.id), + important = !message.important + ) + } + } + + dialog.show() + + } + + private fun onItemLongClick(position: Int): Boolean { + + return true + } + } \ No newline at end of file diff --git a/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryViewModel.kt b/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryViewModel.kt index 7b93fe5a..776877a8 100644 --- a/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryViewModel.kt +++ b/app/src/main/kotlin/com/meloda/fast/screens/messages/MessagesHistoryViewModel.kt @@ -1,13 +1,14 @@ package com.meloda.fast.screens.messages import androidx.lifecycle.viewModelScope -import com.meloda.fast.api.datasource.MessagesDataSource 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.network.request.MessagesGetHistoryRequest -import com.meloda.fast.api.network.request.MessagesSendRequest +import com.meloda.fast.api.model.request.MessagesGetHistoryRequest +import com.meloda.fast.api.model.request.MessagesMarkAsImportantRequest +import com.meloda.fast.api.model.request.MessagesSendRequest +import com.meloda.fast.api.network.datasource.MessagesDataSource import com.meloda.fast.base.viewmodel.BaseViewModel import com.meloda.fast.base.viewmodel.StartProgressEvent import com.meloda.fast.base.viewmodel.StopProgressEvent @@ -109,6 +110,33 @@ class MessagesHistoryViewModel @Inject constructor( }) } + fun markAsImportant( + messagesIds: List, + important: Boolean + ) = viewModelScope.launch { + makeJob({ + dataSource.markAsImportant( + MessagesMarkAsImportantRequest( + messagesIds = messagesIds, + important = important + ) + ) + }, + onAnswer = { + val response = it.response ?: return@makeJob + sendEvent( + MessagesMarkAsImportant( + messagesIds = response, + important = important + ) + ) + }, + onError = { + val throwable = it + val i = 0 + }) + } + } data class MessagesLoaded( @@ -117,4 +145,9 @@ data class MessagesLoaded( val messages: List, val profiles: HashMap, val groups: HashMap +) : VKEvent() + +data class MessagesMarkAsImportant( + val messagesIds: List, + val important: Boolean ) : VKEvent() \ No newline at end of file diff --git a/app/src/main/res/layout/item_message_attachment_photo_in.xml b/app/src/main/res/layout/item_message_attachment_photo_in.xml new file mode 100644 index 00000000..eee4bff7 --- /dev/null +++ b/app/src/main/res/layout/item_message_attachment_photo_in.xml @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_message_attachment_photo_out.xml b/app/src/main/res/layout/item_message_attachment_photo_out.xml new file mode 100644 index 00000000..6bbce4da --- /dev/null +++ b/app/src/main/res/layout/item_message_attachment_photo_out.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_message_service.xml b/app/src/main/res/layout/item_message_service.xml index 3fde4ddf..34d40b12 100644 --- a/app/src/main/res/layout/item_message_service.xml +++ b/app/src/main/res/layout/item_message_service.xml @@ -3,15 +3,19 @@ xmlns:tools="http://schemas.android.com/tools"> + android:gravity="center" + android:orientation="vertical" + android:paddingHorizontal="12dp" + android:paddingVertical="2.5dp"> + android:textColor="?textColorService" + tools:text="Service" /> diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml new file mode 100644 index 00000000..e48bc8e7 --- /dev/null +++ b/app/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index fbf2abae..cdff4e2e 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -10,6 +10,10 @@ @android:color/transparent + true + + @style/PreferenceThemeOverlay + @color/colorPrimary @color/colorPrimaryVariant @color/colorOnPrimary @@ -18,9 +22,18 @@ @color/colorSecondaryVariant @color/colorOnSecondary - true + @color/colorSecondary2 + @color/colorSecondary2Variant + @color/colorOnSecondary2 - @style/PreferenceThemeOverlay + @color/colorSecondary3 + @color/colorSecondary3Variant + @color/colorOnSecondary3 + + @color/textColorPrimary + @color/textColorSecondary + @color/textColorSecondaryVariant + @color/textColorService 12dp diff --git a/app/src/main/res/values-v31/colors.xml b/app/src/main/res/values-v31/colors.xml index d48c5157..ca8ba833 100644 --- a/app/src/main/res/values-v31/colors.xml +++ b/app/src/main/res/values-v31/colors.xml @@ -25,5 +25,6 @@ @android:color/system_neutral2_10 @android:color/system_neutral2_100 @android:color/system_neutral2_500 + @android:color/system_neutral2_600 \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 68202721..e8324453 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -1,9 +1,10 @@ - - - + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index dbcf47c4..bf8f5a92 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -22,6 +22,7 @@ @color/n1_900 @color/n1_900 @color/n2_500 + @color/n2_600 @color/a1_0 @@ -50,5 +51,6 @@ #FDFBFE #E0E2EB #74767D + #5C5E65 diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index b5a6103c..145b8b2f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -30,6 +30,7 @@ @color/textColorPrimary @color/textColorSecondary @color/textColorSecondaryVariant + @color/textColorService @color/colorSurface