forked from melod1n/fast-messenger
improvements in longpoll's stuff
This commit is contained in:
@@ -16,11 +16,11 @@ import dev.meloda.fast.common.LongPollController
|
|||||||
import dev.meloda.fast.common.VkConstants
|
import dev.meloda.fast.common.VkConstants
|
||||||
import dev.meloda.fast.common.extensions.listenValue
|
import dev.meloda.fast.common.extensions.listenValue
|
||||||
import dev.meloda.fast.common.model.LongPollState
|
import dev.meloda.fast.common.model.LongPollState
|
||||||
import dev.meloda.fast.domain.LongPollUpdatesParser
|
|
||||||
import dev.meloda.fast.domain.LongPollUseCase
|
|
||||||
import dev.meloda.fast.data.UserConfig
|
import dev.meloda.fast.data.UserConfig
|
||||||
import dev.meloda.fast.data.processState
|
import dev.meloda.fast.data.processState
|
||||||
import dev.meloda.fast.datastore.AppSettings
|
import dev.meloda.fast.datastore.AppSettings
|
||||||
|
import dev.meloda.fast.domain.LongPollUpdatesParser
|
||||||
|
import dev.meloda.fast.domain.LongPollUseCase
|
||||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||||
import dev.meloda.fast.ui.R
|
import dev.meloda.fast.ui.R
|
||||||
@@ -249,6 +249,7 @@ class LongPollingService : Service() {
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
Log.d(STATE_TAG, "onDestroy")
|
Log.d(STATE_TAG, "onDestroy")
|
||||||
longPollController.updateCurrentState(LongPollState.Stopped)
|
longPollController.updateCurrentState(LongPollState.Stopped)
|
||||||
|
updatesParser.clearListeners()
|
||||||
try {
|
try {
|
||||||
AppSettings.edit { putBoolean(KEY_LONG_POLL_WAS_DESTROYED, true) }
|
AppSettings.edit { putBoolean(KEY_LONG_POLL_WAS_DESTROYED, true) }
|
||||||
job.cancel()
|
job.cancel()
|
||||||
@@ -259,8 +260,7 @@ class LongPollingService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onTrimMemory(level: Int) {
|
override fun onTrimMemory(level: Int) {
|
||||||
Log.d(STATE_TAG, "onTrimMemory")
|
Log.d(STATE_TAG, "onTrimMemory. Level: $level")
|
||||||
longPollController.updateCurrentState(LongPollState.Stopped)
|
|
||||||
super.onTrimMemory(level)
|
super.onTrimMemory(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,15 @@ import dev.meloda.fast.data.processState
|
|||||||
import dev.meloda.fast.model.ApiEvent
|
import dev.meloda.fast.model.ApiEvent
|
||||||
import dev.meloda.fast.model.InteractionType
|
import dev.meloda.fast.model.InteractionType
|
||||||
import dev.meloda.fast.model.LongPollEvent
|
import dev.meloda.fast.model.LongPollEvent
|
||||||
|
import dev.meloda.fast.model.LongPollParsedEvent
|
||||||
|
import dev.meloda.fast.model.MessageFlags
|
||||||
|
import dev.meloda.fast.model.api.domain.VkMessage
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
@@ -25,8 +29,9 @@ class LongPollUpdatesParser(
|
|||||||
) {
|
) {
|
||||||
private val job = SupervisorJob()
|
private val job = SupervisorJob()
|
||||||
|
|
||||||
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
private val exceptionHandler =
|
||||||
Log.d("LongPollUpdatesParser", "error: $throwable")
|
CoroutineExceptionHandler { _, throwable ->
|
||||||
|
Log.e("LongPollUpdatesParser", "error: $throwable")
|
||||||
throwable.printStackTrace()
|
throwable.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +40,8 @@ class LongPollUpdatesParser(
|
|||||||
|
|
||||||
private val coroutineScope = CoroutineScope(coroutineContext)
|
private val coroutineScope = CoroutineScope(coroutineContext)
|
||||||
|
|
||||||
private val listenersMap: MutableMap<ApiEvent, MutableList<VkEventCallback<*>>> = mutableMapOf()
|
private val listenersMap: MutableMap<LongPollEvent, MutableList<VkEventCallback<LongPollParsedEvent>>> =
|
||||||
|
mutableMapOf()
|
||||||
|
|
||||||
fun parseNextUpdate(event: List<Any>) {
|
fun parseNextUpdate(event: List<Any>) {
|
||||||
val eventId = event.first().asInt()
|
val eventId = event.first().asInt()
|
||||||
@@ -49,8 +55,11 @@ class LongPollUpdatesParser(
|
|||||||
ApiEvent.MESSAGE_EDIT -> parseMessageEdit(eventType, event)
|
ApiEvent.MESSAGE_EDIT -> parseMessageEdit(eventType, event)
|
||||||
ApiEvent.MESSAGE_READ_INCOMING -> parseMessageReadIncoming(eventType, event)
|
ApiEvent.MESSAGE_READ_INCOMING -> parseMessageReadIncoming(eventType, event)
|
||||||
ApiEvent.MESSAGE_READ_OUTGOING -> parseMessageReadOutgoing(eventType, event)
|
ApiEvent.MESSAGE_READ_OUTGOING -> parseMessageReadOutgoing(eventType, event)
|
||||||
|
ApiEvent.CHAT_CLEAR_FLAGS -> parseChatClearFlags(eventType, event)
|
||||||
|
ApiEvent.CHAT_SET_FLAGS -> parseChatSetFlags(eventType, event)
|
||||||
ApiEvent.MESSAGES_DELETED -> parseMessagesDeleted(eventType, event)
|
ApiEvent.MESSAGES_DELETED -> parseMessagesDeleted(eventType, event)
|
||||||
ApiEvent.PIN_UNPIN_CONVERSATION -> parseConversationPinStateChanged(eventType, event)
|
ApiEvent.CHAT_MAJOR_CHANGED -> parseChatMajorChanged(eventType, event)
|
||||||
|
ApiEvent.CHAT_MINOR_CHANGED -> parseChatMinorChanged(eventType, event)
|
||||||
|
|
||||||
ApiEvent.TYPING,
|
ApiEvent.TYPING,
|
||||||
ApiEvent.AUDIO_MESSAGE_RECORDING,
|
ApiEvent.AUDIO_MESSAGE_RECORDING,
|
||||||
@@ -74,6 +83,15 @@ class LongPollUpdatesParser(
|
|||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val longPollEvent: LongPollEvent = when (eventType) {
|
||||||
|
ApiEvent.TYPING -> LongPollEvent.TYPING
|
||||||
|
ApiEvent.AUDIO_MESSAGE_RECORDING -> LongPollEvent.AUDIO_MESSAGE_RECORDING
|
||||||
|
ApiEvent.PHOTO_UPLOADING -> LongPollEvent.PHOTO_UPLOADING
|
||||||
|
ApiEvent.VIDEO_UPLOADING -> LongPollEvent.VIDEO_UPLOADING
|
||||||
|
ApiEvent.FILE_UPLOADING -> LongPollEvent.FILE_UPLOADING
|
||||||
|
else -> return
|
||||||
|
}
|
||||||
|
|
||||||
val peerId = event[1].asInt()
|
val peerId = event[1].asInt()
|
||||||
val userIds = event[2].toList(Any::asInt).filter { it != UserConfig.userId }
|
val userIds = event[2].toList(Any::asInt).filter { it != UserConfig.userId }
|
||||||
val totalCount = event[3].asInt()
|
val totalCount = event[3].asInt()
|
||||||
@@ -82,12 +100,11 @@ class LongPollUpdatesParser(
|
|||||||
// if userIds contains only account's id, then we don't need to show our status
|
// if userIds contains only account's id, then we don't need to show our status
|
||||||
if (userIds.isEmpty()) return
|
if (userIds.isEmpty()) return
|
||||||
|
|
||||||
coroutineScope.launch {
|
listenersMap[longPollEvent]?.let { listeners ->
|
||||||
listenersMap[eventType]?.let { listeners ->
|
|
||||||
listeners.forEach { vkEventCallback ->
|
listeners.forEach { vkEventCallback ->
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.Interaction>)
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.Interaction>)
|
||||||
.onEvent(
|
.onEvent(
|
||||||
LongPollEvent.Interaction(
|
LongPollParsedEvent.Interaction(
|
||||||
interactionType = interactionType,
|
interactionType = interactionType,
|
||||||
peerId = peerId,
|
peerId = peerId,
|
||||||
userIds = userIds,
|
userIds = userIds,
|
||||||
@@ -98,7 +115,6 @@ class LongPollUpdatesParser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseUnreadCounterUpdate(eventType: ApiEvent, event: List<Any>) {
|
private fun parseUnreadCounterUpdate(eventType: ApiEvent, event: List<Any>) {
|
||||||
Log.d("LongPollUpdatesParser", "$eventType $event")
|
Log.d("LongPollUpdatesParser", "$eventType $event")
|
||||||
@@ -111,11 +127,11 @@ class LongPollUpdatesParser(
|
|||||||
val archiveUnreadUnmutedCount = event[8].asInt()
|
val archiveUnreadUnmutedCount = event[8].asInt()
|
||||||
val archiveMentionsCount = event[9].asInt()
|
val archiveMentionsCount = event[9].asInt()
|
||||||
|
|
||||||
listenersMap[ApiEvent.UNREAD_COUNT_UPDATE]?.let { listeners ->
|
listenersMap[LongPollEvent.UNREAD_COUNTER_UPDATE]?.let { listeners ->
|
||||||
listeners.forEach { vkEventCallback ->
|
listeners.forEach { vkEventCallback ->
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.UnreadCounter>)
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.UnreadCounter>)
|
||||||
.onEvent(
|
.onEvent(
|
||||||
LongPollEvent.UnreadCounter(
|
LongPollParsedEvent.UnreadCounter(
|
||||||
unread = unreadCount,
|
unread = unreadCount,
|
||||||
unreadUnmuted = unreadUnmutedCount,
|
unreadUnmuted = unreadUnmutedCount,
|
||||||
showOnlyMuted = showOnlyMuted,
|
showOnlyMuted = showOnlyMuted,
|
||||||
@@ -129,31 +145,182 @@ class LongPollUpdatesParser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseConversationPinStateChanged(eventType: ApiEvent, event: List<Any>) {
|
|
||||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
|
||||||
|
|
||||||
val peerId = event[1].asInt()
|
|
||||||
val majorId = event[2].asInt()
|
|
||||||
|
|
||||||
listenersMap[ApiEvent.PIN_UNPIN_CONVERSATION]?.let { listeners ->
|
|
||||||
listeners.forEach { vkEventCallback ->
|
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkConversationPinStateChangedEvent>)
|
|
||||||
.onEvent(
|
|
||||||
LongPollEvent.VkConversationPinStateChangedEvent(
|
|
||||||
peerId = peerId,
|
|
||||||
majorId = majorId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseMessageSetFlags(eventType: ApiEvent, event: List<Any>) {
|
private fun parseMessageSetFlags(eventType: ApiEvent, event: List<Any>) {
|
||||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
|
|
||||||
|
val messageId = event[1].asInt()
|
||||||
|
val flags = event[2].asInt()
|
||||||
|
val peerId = event[3].asInt()
|
||||||
|
|
||||||
|
val eventsToSend = mutableListOf<LongPollParsedEvent>()
|
||||||
|
|
||||||
|
val parsedFlags = MessageFlags.parse(flags)
|
||||||
|
parsedFlags.forEach { flag ->
|
||||||
|
when (flag) {
|
||||||
|
MessageFlags.IMPORTANT -> { // marked as important
|
||||||
|
val eventToSend = LongPollParsedEvent.MessageMarkedAsImportant(
|
||||||
|
peerId = peerId,
|
||||||
|
messageId = messageId,
|
||||||
|
marked = true
|
||||||
|
)
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.MARKED_AS_IMPORTANT]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageMarkedAsImportant>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlags.SPAM -> { // marked as spam
|
||||||
|
val eventToSend = LongPollParsedEvent.MessageMarkedAsSpam(
|
||||||
|
peerId = peerId,
|
||||||
|
messageId = messageId
|
||||||
|
)
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.MARKED_AS_SPAM]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageMarkedAsSpam>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlags.DELETED -> {
|
||||||
|
val eventToSend =
|
||||||
|
if (parsedFlags.contains(MessageFlags.DELETED_FOR_ALL)) { // deleted for all
|
||||||
|
LongPollParsedEvent.MessageDeleted(
|
||||||
|
peerId = peerId,
|
||||||
|
messageId = messageId,
|
||||||
|
forAll = true
|
||||||
|
)
|
||||||
|
} else { // deleted only for me
|
||||||
|
LongPollParsedEvent.MessageDeleted(
|
||||||
|
peerId = peerId,
|
||||||
|
messageId = messageId,
|
||||||
|
forAll = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.MESSAGE_DELETED]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageDeleted>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlags.AUDIO_LISTENED -> { // audio message listened
|
||||||
|
val eventToSend = LongPollParsedEvent.AudioMessageListened(
|
||||||
|
peerId = peerId,
|
||||||
|
messageId = messageId
|
||||||
|
)
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.AUDIO_MESSAGE_LISTENED]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.AudioMessageListened>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventsToSend.forEach { eventToSend ->
|
||||||
|
listenersMap[LongPollEvent.MESSAGE_SET_FLAGS]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent>)?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseMessageClearFlags(eventType: ApiEvent, event: List<Any>) {
|
private fun parseMessageClearFlags(eventType: ApiEvent, event: List<Any>) {
|
||||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
|
|
||||||
|
val messageId = event[1].asInt()
|
||||||
|
val flags = event[2].asInt()
|
||||||
|
val peerId = event[3].asInt()
|
||||||
|
|
||||||
|
val eventsToSend = mutableListOf<LongPollParsedEvent>()
|
||||||
|
|
||||||
|
val parsedFlags = MessageFlags.parse(flags)
|
||||||
|
|
||||||
|
coroutineScope.launch {
|
||||||
|
parsedFlags.forEach { flag ->
|
||||||
|
when (flag) {
|
||||||
|
MessageFlags.IMPORTANT -> { // not important anymore
|
||||||
|
val eventToSend = LongPollParsedEvent.MessageMarkedAsImportant(
|
||||||
|
peerId = peerId,
|
||||||
|
messageId = messageId,
|
||||||
|
marked = false
|
||||||
|
)
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.MARKED_AS_IMPORTANT]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageMarkedAsImportant>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlags.SPAM -> {
|
||||||
|
if (parsedFlags.contains(MessageFlags.CANCEL_SPAM)) { // not spam anymore
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val message = loadMessage(messageId)
|
||||||
|
message?.let {
|
||||||
|
val eventToSend =
|
||||||
|
LongPollParsedEvent.MessageMarkedAsNotSpam(message = message)
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.MARKED_AS_NOT_SPAM]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageMarkedAsNotSpam>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFlags.DELETED -> { // restored
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val message = loadMessage(messageId)
|
||||||
|
message?.let {
|
||||||
|
val eventToSend =
|
||||||
|
LongPollParsedEvent.MessageRestored(message = message)
|
||||||
|
eventsToSend += eventToSend
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.MESSAGE_RESTORED]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageRestored>)
|
||||||
|
?.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventsToSend.forEach { eventToSend ->
|
||||||
|
listenersMap[LongPollEvent.MESSAGE_CLEAR_FLAGS]?.let { listeners ->
|
||||||
|
listeners.map { vkEventCallback ->
|
||||||
|
vkEventCallback.onEvent(eventToSend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseMessageNew(eventType: ApiEvent, event: List<Any>) {
|
private fun parseMessageNew(eventType: ApiEvent, event: List<Any>) {
|
||||||
@@ -161,17 +328,11 @@ class LongPollUpdatesParser(
|
|||||||
val messageId = event[1].asInt()
|
val messageId = event[1].asInt()
|
||||||
|
|
||||||
coroutineScope.launch(Dispatchers.IO) {
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
val newMessageEvent: LongPollEvent.VkMessageNewEvent? =
|
loadMessage(messageId)?.let { message ->
|
||||||
loadNormalMessage(
|
listenersMap[LongPollEvent.MESSAGE_NEW]?.let {
|
||||||
eventType,
|
|
||||||
messageId
|
|
||||||
)
|
|
||||||
|
|
||||||
newMessageEvent?.let { event ->
|
|
||||||
listenersMap[ApiEvent.MESSAGE_NEW]?.let {
|
|
||||||
it.map { vkEventCallback ->
|
it.map { vkEventCallback ->
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageNewEvent>)
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.NewMessage>)
|
||||||
.onEvent(event)
|
.onEvent(LongPollParsedEvent.NewMessage(message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,18 +343,12 @@ class LongPollUpdatesParser(
|
|||||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
val messageId = event[1].asInt()
|
val messageId = event[1].asInt()
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
val editedMessageEvent: LongPollEvent.VkMessageEditEvent? =
|
loadMessage(messageId)?.let { message ->
|
||||||
loadNormalMessage(
|
listenersMap[LongPollEvent.MESSAGE_EDITED]?.let {
|
||||||
eventType,
|
|
||||||
messageId
|
|
||||||
)
|
|
||||||
|
|
||||||
editedMessageEvent?.let { event ->
|
|
||||||
listenersMap[ApiEvent.MESSAGE_EDIT]?.let {
|
|
||||||
it.map { vkEventCallback ->
|
it.map { vkEventCallback ->
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageEditEvent>)
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.MessageEdited>)
|
||||||
.onEvent(event)
|
.onEvent(LongPollParsedEvent.MessageEdited(message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,11 +361,11 @@ class LongPollUpdatesParser(
|
|||||||
val messageId = event[2].asInt()
|
val messageId = event[2].asInt()
|
||||||
val unreadCount = event[3].asInt()
|
val unreadCount = event[3].asInt()
|
||||||
|
|
||||||
listenersMap[ApiEvent.MESSAGE_READ_INCOMING]?.let { listeners ->
|
listenersMap[LongPollEvent.INCOMING_MESSAGE_READ]?.let { listeners ->
|
||||||
listeners.map { vkEventCallback ->
|
listeners.map { vkEventCallback ->
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageReadIncomingEvent>)
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.IncomingMessageRead>)
|
||||||
.onEvent(
|
.onEvent(
|
||||||
LongPollEvent.VkMessageReadIncomingEvent(
|
LongPollParsedEvent.IncomingMessageRead(
|
||||||
peerId = peerId,
|
peerId = peerId,
|
||||||
messageId = messageId,
|
messageId = messageId,
|
||||||
unreadCount = unreadCount
|
unreadCount = unreadCount
|
||||||
@@ -226,11 +381,11 @@ class LongPollUpdatesParser(
|
|||||||
val messageId = event[2].asInt()
|
val messageId = event[2].asInt()
|
||||||
val unreadCount = event[3].asInt()
|
val unreadCount = event[3].asInt()
|
||||||
|
|
||||||
listenersMap[ApiEvent.MESSAGE_READ_OUTGOING]?.let { listeners ->
|
listenersMap[LongPollEvent.OUTGOING_MESSAGE_READ]?.let { listeners ->
|
||||||
listeners.map { vkEventCallback ->
|
listeners.map { vkEventCallback ->
|
||||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageReadOutgoingEvent>)
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.OutgoingMessageRead>)
|
||||||
.onEvent(
|
.onEvent(
|
||||||
LongPollEvent.VkMessageReadOutgoingEvent(
|
LongPollParsedEvent.OutgoingMessageRead(
|
||||||
peerId = peerId,
|
peerId = peerId,
|
||||||
messageId = messageId,
|
messageId = messageId,
|
||||||
unreadCount = unreadCount
|
unreadCount = unreadCount
|
||||||
@@ -240,14 +395,72 @@ class LongPollUpdatesParser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseMessagesDeleted(eventType: ApiEvent, event: List<Any>) {
|
private fun parseChatClearFlags(eventType: ApiEvent, event: List<Any>) {
|
||||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun <reified T : LongPollEvent> loadNormalMessage(
|
private fun parseChatSetFlags(eventType: ApiEvent, event: List<Any>) {
|
||||||
eventType: ApiEvent,
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
messageId: Int
|
}
|
||||||
): T? = suspendCoroutine { continuation ->
|
|
||||||
|
private fun parseMessagesDeleted(eventType: ApiEvent, event: List<Any>) {
|
||||||
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
|
|
||||||
|
val peerId = event[1].asInt()
|
||||||
|
val messageId = event[2].asInt()
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.CHAT_CLEARED]?.let { listeners ->
|
||||||
|
listeners.forEach { vkEventCallback ->
|
||||||
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.ChatCleared>)
|
||||||
|
.onEvent(
|
||||||
|
LongPollParsedEvent.ChatCleared(
|
||||||
|
peerId = peerId,
|
||||||
|
toMessageId = messageId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseChatMajorChanged(eventType: ApiEvent, event: List<Any>) {
|
||||||
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
|
|
||||||
|
val peerId = event[1].asInt()
|
||||||
|
val majorId = event[2].asInt()
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.CHAT_MAJOR_CHANGED]?.let { listeners ->
|
||||||
|
listeners.forEach { vkEventCallback ->
|
||||||
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.ChatMajorChanged>)
|
||||||
|
.onEvent(
|
||||||
|
LongPollParsedEvent.ChatMajorChanged(
|
||||||
|
peerId = peerId,
|
||||||
|
majorId = majorId,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseChatMinorChanged(eventType: ApiEvent, event: List<Any>) {
|
||||||
|
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||||
|
|
||||||
|
val peerId = event[1].asInt()
|
||||||
|
val minorId = event[2].asInt()
|
||||||
|
|
||||||
|
listenersMap[LongPollEvent.CHAT_MINOR_CHANGED]?.let { listeners ->
|
||||||
|
listeners.forEach { vkEventCallback ->
|
||||||
|
(vkEventCallback as VkEventCallback<LongPollParsedEvent.ChatMinorChanged>)
|
||||||
|
.onEvent(
|
||||||
|
LongPollParsedEvent.ChatMinorChanged(
|
||||||
|
peerId = peerId,
|
||||||
|
minorId = minorId,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun loadMessage(messageId: Int): VkMessage? = suspendCoroutine { continuation ->
|
||||||
coroutineScope.launch(Dispatchers.IO) {
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
messagesUseCase.getById(
|
messagesUseCase.getById(
|
||||||
messageIds = listOf(messageId),
|
messageIds = listOf(messageId),
|
||||||
@@ -256,10 +469,11 @@ class LongPollUpdatesParser(
|
|||||||
).listenValue(this) { state ->
|
).listenValue(this) { state ->
|
||||||
state.processState(
|
state.processState(
|
||||||
error = { error ->
|
error = { error ->
|
||||||
Log.e("LongPollUpdatesParser", "loadNormalMessage: error: $error")
|
Log.e("LongPollUpdatesParser", "loadMessage: error: $error")
|
||||||
|
continuation.resume(null)
|
||||||
},
|
},
|
||||||
success = { messages ->
|
success = { response ->
|
||||||
val message = messages.singleOrNull() ?: run {
|
val message = response.singleOrNull() ?: run {
|
||||||
continuation.resume(null)
|
continuation.resume(null)
|
||||||
return@listenValue
|
return@listenValue
|
||||||
}
|
}
|
||||||
@@ -267,107 +481,113 @@ class LongPollUpdatesParser(
|
|||||||
VkMemoryCache[message.id] = message
|
VkMemoryCache[message.id] = message
|
||||||
messagesUseCase.storeMessage(message)
|
messagesUseCase.storeMessage(message)
|
||||||
|
|
||||||
val resumeValue: LongPollEvent? = when (eventType) {
|
continuation.resume(message)
|
||||||
ApiEvent.MESSAGE_NEW -> LongPollEvent.VkMessageNewEvent(message)
|
|
||||||
ApiEvent.MESSAGE_EDIT -> LongPollEvent.VkMessageEditEvent(message)
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
continuation.resume(null)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resumeValue?.let { value -> continuation.resume(value as T) }
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : LongPollEvent> registerListener(
|
@Suppress("UNCHECKED_CAST")
|
||||||
eventType: ApiEvent,
|
private fun <T : LongPollParsedEvent> registerListener(
|
||||||
|
eventType: LongPollEvent,
|
||||||
listener: VkEventCallback<T>
|
listener: VkEventCallback<T>
|
||||||
) {
|
) {
|
||||||
listenersMap.let { map ->
|
listenersMap.let { map ->
|
||||||
map[eventType] = (map[eventType] ?: mutableListOf()).also { it.add(listener) }
|
map[eventType] = (map[eventType] ?: mutableListOf())
|
||||||
|
.also {
|
||||||
|
it.add(listener as VkEventCallback<LongPollParsedEvent>)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : LongPollEvent> registerListeners(
|
private fun <T : LongPollParsedEvent> registerListeners(
|
||||||
eventTypes: List<ApiEvent>,
|
eventTypes: List<LongPollEvent>,
|
||||||
listener: VkEventCallback<T>
|
listener: VkEventCallback<T>
|
||||||
) {
|
) {
|
||||||
eventTypes.forEach { eventType -> registerListener(eventType, listener) }
|
eventTypes.forEach { eventType -> registerListener(eventType, listener) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onConversationPinStateChanged(listener: VkEventCallback<LongPollEvent.VkConversationPinStateChangedEvent>) {
|
fun onMessageSetFlags(block: (LongPollParsedEvent) -> Unit) {
|
||||||
registerListener(ApiEvent.PIN_UNPIN_CONVERSATION, listener)
|
registerListener(LongPollEvent.MESSAGE_SET_FLAGS, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onConversationPinStateChanged(block: (LongPollEvent.VkConversationPinStateChangedEvent) -> Unit) {
|
fun onMessageMarkedAsImportant(block: (LongPollParsedEvent.MessageMarkedAsImportant) -> Unit) {
|
||||||
onConversationPinStateChanged(assembleEventCallback(block))
|
registerListener(LongPollEvent.MARKED_AS_IMPORTANT, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageIncomingRead(listener: VkEventCallback<LongPollEvent.VkMessageReadIncomingEvent>) {
|
fun onMessageMarkedAsSpam(block: (LongPollParsedEvent.MessageMarkedAsSpam) -> Unit) {
|
||||||
registerListener(ApiEvent.MESSAGE_READ_INCOMING, listener)
|
registerListener(LongPollEvent.MARKED_AS_SPAM, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageIncomingRead(block: (LongPollEvent.VkMessageReadIncomingEvent) -> Unit) {
|
fun onMessageDeleted(block: (LongPollParsedEvent.MessageDeleted) -> Unit) {
|
||||||
onMessageIncomingRead(assembleEventCallback(block))
|
registerListener(LongPollEvent.MESSAGE_DELETED, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageOutgoingRead(listener: VkEventCallback<LongPollEvent.VkMessageReadOutgoingEvent>) {
|
fun onMessageClearFlags(block: (LongPollParsedEvent) -> Unit) {
|
||||||
registerListener(ApiEvent.MESSAGE_READ_OUTGOING, listener)
|
registerListener(LongPollEvent.MESSAGE_CLEAR_FLAGS, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageOutgoingRead(block: (LongPollEvent.VkMessageReadOutgoingEvent) -> Unit) {
|
fun onMessageMarkedAsNotSpam(block: (LongPollParsedEvent.MessageMarkedAsNotSpam) -> Unit) {
|
||||||
onMessageOutgoingRead(assembleEventCallback(block))
|
registerListener(LongPollEvent.MARKED_AS_NOT_SPAM, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onNewMessage(listener: VkEventCallback<LongPollEvent.VkMessageNewEvent>) {
|
fun onMessageRestored(block: (LongPollParsedEvent.MessageRestored) -> Unit) {
|
||||||
registerListener(ApiEvent.MESSAGE_NEW, listener)
|
registerListener(LongPollEvent.MESSAGE_RESTORED, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onNewMessage(block: (LongPollEvent.VkMessageNewEvent) -> Unit) {
|
fun onNewMessage(block: (LongPollParsedEvent.NewMessage) -> Unit) {
|
||||||
onNewMessage(assembleEventCallback(block))
|
registerListener(LongPollEvent.MESSAGE_NEW, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageEdited(listener: VkEventCallback<LongPollEvent.VkMessageEditEvent>) {
|
fun onMessageEdited(block: (LongPollParsedEvent.MessageEdited) -> Unit) {
|
||||||
registerListener(ApiEvent.MESSAGE_EDIT, listener)
|
registerListener(LongPollEvent.MESSAGE_EDITED, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMessageEdited(block: (LongPollEvent.VkMessageEditEvent) -> Unit) {
|
fun onMessageIncomingRead(block: (LongPollParsedEvent.IncomingMessageRead) -> Unit) {
|
||||||
onMessageEdited(assembleEventCallback(block))
|
registerListener(LongPollEvent.INCOMING_MESSAGE_READ, assembleEventCallback(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onInteractions(listener: VkEventCallback<LongPollEvent.Interaction>) {
|
fun onMessageOutgoingRead(block: (LongPollParsedEvent.OutgoingMessageRead) -> Unit) {
|
||||||
|
registerListener(LongPollEvent.OUTGOING_MESSAGE_READ, assembleEventCallback(block))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onChatCleared(block: (LongPollParsedEvent.ChatCleared) -> Unit) {
|
||||||
|
registerListener(LongPollEvent.CHAT_CLEARED, assembleEventCallback(block))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onChatMajorChanged(block: (LongPollParsedEvent.ChatMajorChanged) -> Unit) {
|
||||||
|
registerListener(LongPollEvent.CHAT_MAJOR_CHANGED, assembleEventCallback(block))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onChatMinorChanged(block: (LongPollParsedEvent.ChatMinorChanged) -> Unit) {
|
||||||
|
registerListener(LongPollEvent.CHAT_MINOR_CHANGED, assembleEventCallback(block))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onInteractions(block: (LongPollParsedEvent.Interaction) -> Unit) {
|
||||||
registerListeners(
|
registerListeners(
|
||||||
eventTypes = listOf(
|
eventTypes = listOf(
|
||||||
ApiEvent.TYPING,
|
LongPollEvent.TYPING,
|
||||||
ApiEvent.AUDIO_MESSAGE_RECORDING,
|
LongPollEvent.AUDIO_MESSAGE_RECORDING,
|
||||||
ApiEvent.PHOTO_UPLOADING,
|
LongPollEvent.PHOTO_UPLOADING,
|
||||||
ApiEvent.VIDEO_UPLOADING,
|
LongPollEvent.VIDEO_UPLOADING,
|
||||||
ApiEvent.FILE_UPLOADING
|
LongPollEvent.FILE_UPLOADING
|
||||||
),
|
),
|
||||||
listener = listener
|
listener = assembleEventCallback(block)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onInteractions(block: (LongPollEvent.Interaction) -> Unit) {
|
|
||||||
onInteractions(assembleEventCallback(block))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearListeners() {
|
fun clearListeners() {
|
||||||
listenersMap.clear()
|
listenersMap.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal inline fun <R : LongPollEvent> assembleEventCallback(
|
internal inline fun <R : LongPollParsedEvent> assembleEventCallback(
|
||||||
crossinline block: (R) -> Unit,
|
crossinline block: (R) -> Unit,
|
||||||
): VkEventCallback<R> {
|
): VkEventCallback<R> {
|
||||||
return VkEventCallback { event -> block.invoke(event) }
|
return VkEventCallback { event -> block.invoke(event) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interface VkEventCallback<in T : LongPollEvent> {
|
fun interface VkEventCallback<in T : LongPollParsedEvent> {
|
||||||
fun onEvent(event: T)
|
fun onEvent(event: T)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ enum class ApiEvent(val value: Int) {
|
|||||||
MESSAGE_EDIT(5),
|
MESSAGE_EDIT(5),
|
||||||
MESSAGE_READ_INCOMING(6),
|
MESSAGE_READ_INCOMING(6),
|
||||||
MESSAGE_READ_OUTGOING(7),
|
MESSAGE_READ_OUTGOING(7),
|
||||||
|
CHAT_CLEAR_FLAGS(10),
|
||||||
|
CHAT_SET_FLAGS(12),
|
||||||
MESSAGES_DELETED(13),
|
MESSAGES_DELETED(13),
|
||||||
PIN_UNPIN_CONVERSATION(20),
|
CHAT_MAJOR_CHANGED(20),
|
||||||
|
CHAT_MINOR_CHANGED(21),
|
||||||
TYPING(63),
|
TYPING(63),
|
||||||
AUDIO_MESSAGE_RECORDING(64),
|
AUDIO_MESSAGE_RECORDING(64),
|
||||||
PHOTO_UPLOADING(65),
|
PHOTO_UPLOADING(65),
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.meloda.fast.model
|
||||||
|
|
||||||
|
enum class ConversationFlags(val value: Int) {
|
||||||
|
DISABLE_PUSH(16),
|
||||||
|
DISABLE_SOUND(32),
|
||||||
|
INCOMING_CHAT_REQUEST(256),
|
||||||
|
DECLINED_CHAT_REQUEST(512),
|
||||||
|
MENTION(1024),
|
||||||
|
HIDE_CHAT_FROM_SEARCH(2048),
|
||||||
|
BUSINESS_CHAT(8192),
|
||||||
|
MARKED_MESSAGE(16384), // mention or disappearing message
|
||||||
|
DO_NOT_NOTIFY_MENTIONS_ALL_ONLINE(262144),
|
||||||
|
DO_NOT_NOTIFY_ALL_MENTIONS(524288),
|
||||||
|
MARKED_AS_UNREAD(1048576),
|
||||||
|
ARCHIVED(8388608),
|
||||||
|
CALL_IN_PROGRESS(16777216),
|
||||||
|
}
|
||||||
@@ -1,45 +1,27 @@
|
|||||||
package dev.meloda.fast.model
|
package dev.meloda.fast.model
|
||||||
|
|
||||||
import dev.meloda.fast.model.api.domain.VkMessage
|
enum class LongPollEvent {
|
||||||
|
MESSAGE_SET_FLAGS,
|
||||||
sealed interface LongPollEvent {
|
MESSAGE_CLEAR_FLAGS,
|
||||||
|
MESSAGE_NEW,
|
||||||
data class VkMessageNewEvent(val message: VkMessage) : LongPollEvent
|
MESSAGE_EDITED,
|
||||||
|
INCOMING_MESSAGE_READ,
|
||||||
data class VkMessageEditEvent(val message: VkMessage) : LongPollEvent
|
OUTGOING_MESSAGE_READ,
|
||||||
|
CHAT_SET_FLAGS,
|
||||||
data class VkMessageReadIncomingEvent(
|
CHAT_CLEAR_FLAGS,
|
||||||
val peerId: Int,
|
CHAT_MAJOR_CHANGED,
|
||||||
val messageId: Int,
|
CHAT_MINOR_CHANGED,
|
||||||
val unreadCount: Int,
|
TYPING,
|
||||||
) : LongPollEvent
|
AUDIO_MESSAGE_RECORDING,
|
||||||
|
PHOTO_UPLOADING,
|
||||||
data class VkMessageReadOutgoingEvent(
|
VIDEO_UPLOADING,
|
||||||
val peerId: Int,
|
FILE_UPLOADING,
|
||||||
val messageId: Int,
|
UNREAD_COUNTER_UPDATE,
|
||||||
val unreadCount: Int,
|
MARKED_AS_IMPORTANT,
|
||||||
) : LongPollEvent
|
MARKED_AS_SPAM,
|
||||||
|
MARKED_AS_NOT_SPAM,
|
||||||
data class VkConversationPinStateChangedEvent(
|
MESSAGE_DELETED,
|
||||||
val peerId: Int,
|
MESSAGE_RESTORED,
|
||||||
val majorId: Int,
|
AUDIO_MESSAGE_LISTENED,
|
||||||
) : LongPollEvent
|
CHAT_CLEARED
|
||||||
|
|
||||||
data class Interaction(
|
|
||||||
val interactionType: InteractionType,
|
|
||||||
val peerId: Int,
|
|
||||||
val userIds: List<Int>,
|
|
||||||
val totalCount: Int,
|
|
||||||
val timestamp: Int
|
|
||||||
) : LongPollEvent
|
|
||||||
|
|
||||||
data class UnreadCounter(
|
|
||||||
val unread: Int,
|
|
||||||
val unreadUnmuted: Int,
|
|
||||||
val showOnlyMuted: Boolean,
|
|
||||||
val business: Int,
|
|
||||||
val archive: Int,
|
|
||||||
val archiveUnmuted: Int,
|
|
||||||
val archiveMentions: Int
|
|
||||||
): LongPollEvent
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package dev.meloda.fast.model
|
||||||
|
|
||||||
|
import dev.meloda.fast.model.api.domain.VkMessage
|
||||||
|
|
||||||
|
sealed interface LongPollParsedEvent {
|
||||||
|
|
||||||
|
data class NewMessage(val message: VkMessage) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class MessageEdited(val message: VkMessage) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class IncomingMessageRead(
|
||||||
|
val peerId: Int,
|
||||||
|
val messageId: Int,
|
||||||
|
val unreadCount: Int,
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class OutgoingMessageRead(
|
||||||
|
val peerId: Int,
|
||||||
|
val messageId: Int,
|
||||||
|
val unreadCount: Int,
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class ChatMajorChanged(
|
||||||
|
val peerId: Int,
|
||||||
|
val majorId: Int,
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class ChatMinorChanged(
|
||||||
|
val peerId: Int,
|
||||||
|
val minorId: Int
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class Interaction(
|
||||||
|
val interactionType: InteractionType,
|
||||||
|
val peerId: Int,
|
||||||
|
val userIds: List<Int>,
|
||||||
|
val totalCount: Int,
|
||||||
|
val timestamp: Int
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class UnreadCounter(
|
||||||
|
val unread: Int,
|
||||||
|
val unreadUnmuted: Int,
|
||||||
|
val showOnlyMuted: Boolean,
|
||||||
|
val business: Int,
|
||||||
|
val archive: Int,
|
||||||
|
val archiveUnmuted: Int,
|
||||||
|
val archiveMentions: Int
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class MessageMarkedAsImportant(
|
||||||
|
val peerId: Int,
|
||||||
|
val messageId: Int,
|
||||||
|
val marked: Boolean
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class MessageMarkedAsSpam(
|
||||||
|
val peerId: Int,
|
||||||
|
val messageId: Int
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class MessageMarkedAsNotSpam(
|
||||||
|
val message: VkMessage
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class MessageDeleted(
|
||||||
|
val peerId: Int,
|
||||||
|
val messageId: Int,
|
||||||
|
val forAll: Boolean
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class MessageRestored(
|
||||||
|
val message: VkMessage
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class AudioMessageListened(
|
||||||
|
val peerId: Int,
|
||||||
|
val messageId: Int
|
||||||
|
) : LongPollParsedEvent
|
||||||
|
|
||||||
|
data class ChatCleared(
|
||||||
|
val peerId: Int,
|
||||||
|
val toMessageId: Int
|
||||||
|
): LongPollParsedEvent
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package dev.meloda.fast.model
|
||||||
|
|
||||||
|
enum class MessageFlags(val value: Int) {
|
||||||
|
UNREAD(1),
|
||||||
|
OUTGOING(2),
|
||||||
|
IMPORTANT(8),
|
||||||
|
SPAM(64),
|
||||||
|
DELETED(128),
|
||||||
|
AUDIO_LISTENED(4096),
|
||||||
|
FROM_GROUP_CHAT(8192),
|
||||||
|
CANCEL_SPAM(32768),
|
||||||
|
DELETED_FOR_ALL(131072),
|
||||||
|
DO_NOT_SHOW_NOTIFICATION(1048576),
|
||||||
|
MESSAGE_WITH_REPLY(2097152),
|
||||||
|
REACTION(16777216);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun parse(mask: Int): List<MessageFlags> {
|
||||||
|
val flags = mutableListOf<MessageFlags>()
|
||||||
|
|
||||||
|
entries.forEach { flag ->
|
||||||
|
if (mask and flag.value > 0) {
|
||||||
|
flags.add(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+106
-38
@@ -23,7 +23,7 @@ import dev.meloda.fast.domain.LongPollUpdatesParser
|
|||||||
import dev.meloda.fast.domain.MessagesUseCase
|
import dev.meloda.fast.domain.MessagesUseCase
|
||||||
import dev.meloda.fast.model.BaseError
|
import dev.meloda.fast.model.BaseError
|
||||||
import dev.meloda.fast.model.InteractionType
|
import dev.meloda.fast.model.InteractionType
|
||||||
import dev.meloda.fast.model.LongPollEvent
|
import dev.meloda.fast.model.LongPollParsedEvent
|
||||||
import dev.meloda.fast.model.api.domain.VkConversation
|
import dev.meloda.fast.model.api.domain.VkConversation
|
||||||
import dev.meloda.fast.network.VkErrorCode
|
import dev.meloda.fast.network.VkErrorCode
|
||||||
import dev.meloda.fast.ui.model.api.ConversationOption
|
import dev.meloda.fast.ui.model.api.ConversationOption
|
||||||
@@ -104,8 +104,10 @@ class ConversationsViewModelImpl(
|
|||||||
updatesParser.onMessageEdited(::handleEditedMessage)
|
updatesParser.onMessageEdited(::handleEditedMessage)
|
||||||
updatesParser.onMessageIncomingRead(::handleReadIncomingMessage)
|
updatesParser.onMessageIncomingRead(::handleReadIncomingMessage)
|
||||||
updatesParser.onMessageOutgoingRead(::handleReadOutgoingMessage)
|
updatesParser.onMessageOutgoingRead(::handleReadOutgoingMessage)
|
||||||
updatesParser.onConversationPinStateChanged(::handlePinStateChanged)
|
|
||||||
updatesParser.onInteractions(::handleInteraction)
|
updatesParser.onInteractions(::handleInteraction)
|
||||||
|
updatesParser.onChatMajorChanged(::handleChatMajorChanged)
|
||||||
|
updatesParser.onChatMinorChanged(::handleChatMinorChanged)
|
||||||
|
updatesParser.onChatCleared(::handleChatClearing)
|
||||||
|
|
||||||
loadConversations()
|
loadConversations()
|
||||||
}
|
}
|
||||||
@@ -383,11 +385,11 @@ class ConversationsViewModelImpl(
|
|||||||
|
|
||||||
},
|
},
|
||||||
success = {
|
success = {
|
||||||
handlePinStateChanged(
|
handleChatMajorChanged(
|
||||||
LongPollEvent.VkConversationPinStateChangedEvent(
|
LongPollParsedEvent.ChatMajorChanged(
|
||||||
peerId = peerId,
|
peerId = peerId,
|
||||||
majorId = if (pin) {
|
majorId = if (pin) {
|
||||||
(pinnedConversationsCount.value + 1) * 16
|
pinnedConversationsCount.value.plus(1) * 16
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@@ -400,7 +402,7 @@ class ConversationsViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNewMessage(event: LongPollEvent.VkMessageNewEvent) {
|
private fun handleNewMessage(event: LongPollParsedEvent.NewMessage) {
|
||||||
val message = event.message
|
val message = event.message
|
||||||
|
|
||||||
val newConversations = conversations.value.toMutableList()
|
val newConversations = conversations.value.toMutableList()
|
||||||
@@ -487,7 +489,7 @@ class ConversationsViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEditedMessage(event: LongPollEvent.VkMessageEditEvent) {
|
private fun handleEditedMessage(event: LongPollParsedEvent.MessageEdited) {
|
||||||
val message = event.message
|
val message = event.message
|
||||||
val newConversations = conversations.value.toMutableList()
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
|
||||||
@@ -516,7 +518,7 @@ class ConversationsViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadIncomingMessage(event: LongPollEvent.VkMessageReadIncomingEvent) {
|
private fun handleReadIncomingMessage(event: LongPollParsedEvent.IncomingMessageRead) {
|
||||||
val newConversations = conversations.value.toMutableList()
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
|
||||||
val conversationIndex =
|
val conversationIndex =
|
||||||
@@ -546,7 +548,7 @@ class ConversationsViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadOutgoingMessage(event: LongPollEvent.VkMessageReadOutgoingEvent) {
|
private fun handleReadOutgoingMessage(event: LongPollParsedEvent.OutgoingMessageRead) {
|
||||||
val newConversations = conversations.value.toMutableList()
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
|
||||||
val conversationIndex =
|
val conversationIndex =
|
||||||
@@ -575,47 +577,113 @@ class ConversationsViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handlePinStateChanged(event: LongPollEvent.VkConversationPinStateChangedEvent) {
|
private fun handleChatMajorChanged(event: LongPollParsedEvent.ChatMajorChanged) {
|
||||||
var pinnedCount = pinnedConversationsCount.value
|
|
||||||
val newConversations = conversations.value.toMutableList()
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
|
||||||
val conversationIndex =
|
val conversationIndex =
|
||||||
newConversations.indexOfFirstOrNull { it.id == event.peerId }
|
newConversations.indexOfFirstOrNull { it.id == event.peerId }
|
||||||
|
|
||||||
if (conversationIndex == null) { // диалога нет в списке
|
if (conversationIndex == null) { // диалога нет в списке
|
||||||
// pizdets
|
// pizdets
|
||||||
} else {
|
} else {
|
||||||
val pin = event.majorId > 0
|
newConversations[conversationIndex] =
|
||||||
|
newConversations[conversationIndex].copy(majorId = event.majorId)
|
||||||
val conversation = newConversations[conversationIndex].copy(majorId = event.majorId)
|
|
||||||
|
|
||||||
newConversations.removeAt(conversationIndex)
|
|
||||||
|
|
||||||
if (pin) {
|
|
||||||
newConversations.add(0, conversation)
|
|
||||||
} else {
|
|
||||||
pinnedCount -= 1
|
|
||||||
|
|
||||||
newConversations.add(conversation)
|
|
||||||
|
|
||||||
val pinnedSubList = newConversations.filter(VkConversation::isPinned)
|
|
||||||
val unpinnedSubList = newConversations
|
|
||||||
.filterNot(VkConversation::isPinned)
|
|
||||||
.sortedByDescending { it.lastMessage?.date }
|
|
||||||
|
|
||||||
newConversations.clear()
|
|
||||||
newConversations += pinnedSubList + unpinnedSubList
|
|
||||||
}
|
|
||||||
|
|
||||||
conversations.update { newConversations }
|
|
||||||
|
|
||||||
|
conversations.setValue { newConversations }
|
||||||
screenState.setValue { old ->
|
screenState.setValue { old ->
|
||||||
old.copy(conversations = newConversations.map {
|
old.copy(
|
||||||
|
conversations = newConversations.map {
|
||||||
it.asPresentation(
|
it.asPresentation(
|
||||||
resources = resources,
|
resources = resources,
|
||||||
useContactName = useContactNames
|
useContactName = useContactNames
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sortConversations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleChatMinorChanged(event: LongPollParsedEvent.ChatMinorChanged) {
|
||||||
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
val conversationIndex =
|
||||||
|
newConversations.indexOfFirstOrNull { it.id == event.peerId }
|
||||||
|
|
||||||
|
if (conversationIndex == null) { // диалога нет в списке
|
||||||
|
// pizdets
|
||||||
|
} else {
|
||||||
|
newConversations[conversationIndex] =
|
||||||
|
newConversations[conversationIndex].copy(minorId = event.minorId)
|
||||||
|
|
||||||
|
conversations.setValue { newConversations }
|
||||||
|
screenState.setValue { old ->
|
||||||
|
old.copy(
|
||||||
|
conversations = newConversations.map {
|
||||||
|
it.asPresentation(
|
||||||
|
resources = resources,
|
||||||
|
useContactName = useContactNames
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sortConversations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sortConversations() {
|
||||||
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
val pinnedConversations = newConversations
|
||||||
|
.filter(VkConversation::isPinned)
|
||||||
|
.sortedWith { c1, c2 ->
|
||||||
|
val diff = c2.majorId - c1.majorId
|
||||||
|
|
||||||
|
if (diff == 0) {
|
||||||
|
c2.minorId - c1.minorId
|
||||||
|
} else {
|
||||||
|
diff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newConversations.removeAll(pinnedConversations)
|
||||||
|
newConversations.sortWith { c1, c2 ->
|
||||||
|
(c2.lastMessage?.date ?: 0) - (c1.lastMessage?.date ?: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
newConversations.addAll(0, pinnedConversations)
|
||||||
|
|
||||||
|
conversations.update { newConversations }
|
||||||
|
screenState.setValue { old ->
|
||||||
|
old.copy(
|
||||||
|
conversations = newConversations.map {
|
||||||
|
it.asPresentation(
|
||||||
|
resources = resources,
|
||||||
|
useContactName = useContactNames
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleChatClearing(event: LongPollParsedEvent.ChatCleared) {
|
||||||
|
val newConversations = conversations.value.toMutableList()
|
||||||
|
|
||||||
|
val conversationIndex = newConversations.indexOfFirstOrNull { it.id == event.peerId }
|
||||||
|
|
||||||
|
if (conversationIndex == null) { // диалога нет в списке
|
||||||
|
// pizdets
|
||||||
|
} else {
|
||||||
|
newConversations.removeAt(conversationIndex)
|
||||||
|
|
||||||
|
conversations.setValue { newConversations }
|
||||||
|
|
||||||
|
screenState.setValue { old ->
|
||||||
|
old.copy(
|
||||||
|
conversations = newConversations.map {
|
||||||
|
it.asPresentation(
|
||||||
|
resources = resources,
|
||||||
|
useContactName = useContactNames
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -629,7 +697,7 @@ class ConversationsViewModelImpl(
|
|||||||
|
|
||||||
private object NewInteractionException : CancellationException()
|
private object NewInteractionException : CancellationException()
|
||||||
|
|
||||||
private fun handleInteraction(event: LongPollEvent.Interaction) {
|
private fun handleInteraction(event: LongPollParsedEvent.Interaction) {
|
||||||
val interactionType = event.interactionType
|
val interactionType = event.interactionType
|
||||||
val peerId = event.peerId
|
val peerId = event.peerId
|
||||||
val userIds = event.userIds
|
val userIds = event.userIds
|
||||||
|
|||||||
+5
-5
@@ -32,7 +32,7 @@ import dev.meloda.fast.messageshistory.util.extractAvatar
|
|||||||
import dev.meloda.fast.messageshistory.util.extractTitle
|
import dev.meloda.fast.messageshistory.util.extractTitle
|
||||||
import dev.meloda.fast.messageshistory.util.findMessageById
|
import dev.meloda.fast.messageshistory.util.findMessageById
|
||||||
import dev.meloda.fast.model.BaseError
|
import dev.meloda.fast.model.BaseError
|
||||||
import dev.meloda.fast.model.LongPollEvent
|
import dev.meloda.fast.model.LongPollParsedEvent
|
||||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||||
import dev.meloda.fast.model.api.domain.VkMessage
|
import dev.meloda.fast.model.api.domain.VkMessage
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -158,7 +158,7 @@ class MessagesHistoryViewModelImpl(
|
|||||||
loadMessagesHistory()
|
loadMessagesHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNewMessage(event: LongPollEvent.VkMessageNewEvent) {
|
private fun handleNewMessage(event: LongPollParsedEvent.NewMessage) {
|
||||||
val message = event.message
|
val message = event.message
|
||||||
|
|
||||||
Log.d("MessagesHistoryViewModel", "handleNewMessage: $message")
|
Log.d("MessagesHistoryViewModel", "handleNewMessage: $message")
|
||||||
@@ -200,7 +200,7 @@ class MessagesHistoryViewModelImpl(
|
|||||||
screenState.setValue { old -> old.copy(messages = newMessages) }
|
screenState.setValue { old -> old.copy(messages = newMessages) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEditedMessage(event: LongPollEvent.VkMessageEditEvent) {
|
private fun handleEditedMessage(event: LongPollParsedEvent.MessageEdited) {
|
||||||
val message = event.message
|
val message = event.message
|
||||||
if (message.peerId != screenState.value.conversationId) return
|
if (message.peerId != screenState.value.conversationId) return
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ class MessagesHistoryViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadIncomingEvent(event: LongPollEvent.VkMessageReadIncomingEvent) {
|
private fun handleReadIncomingEvent(event: LongPollParsedEvent.IncomingMessageRead) {
|
||||||
if (event.peerId != screenState.value.conversationId) return
|
if (event.peerId != screenState.value.conversationId) return
|
||||||
|
|
||||||
val messages = messages.value
|
val messages = messages.value
|
||||||
@@ -257,7 +257,7 @@ class MessagesHistoryViewModelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleReadOutgoingEvent(event: LongPollEvent.VkMessageReadOutgoingEvent) {
|
private fun handleReadOutgoingEvent(event: LongPollParsedEvent.OutgoingMessageRead) {
|
||||||
if (event.peerId != screenState.value.conversationId) return
|
if (event.peerId != screenState.value.conversationId) return
|
||||||
|
|
||||||
val messages = messages.value
|
val messages = messages.value
|
||||||
|
|||||||
Reference in New Issue
Block a user