refactor: unify db refresh flows
This commit is contained in:
@@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -45,6 +46,14 @@ fun <T> Flow<T>.listenValue(
|
||||
action: suspend (T) -> Unit
|
||||
): Job = onEach(action::invoke).launchIn(coroutineScope)
|
||||
|
||||
fun CoroutineScope.launchDbRefresh(
|
||||
load: suspend () -> Unit,
|
||||
after: suspend () -> Unit
|
||||
): Job = launch {
|
||||
load()
|
||||
after()
|
||||
}
|
||||
|
||||
fun createTimerFlow(
|
||||
time: Int,
|
||||
onStartAction: (suspend () -> Unit)? = null,
|
||||
|
||||
@@ -26,6 +26,7 @@ object UserConfig {
|
||||
userId = -1
|
||||
trustedHash = null
|
||||
exchangeToken = null
|
||||
AppSettings.LongPoll.clear()
|
||||
}
|
||||
|
||||
fun isLoggedIn(): Boolean {
|
||||
|
||||
@@ -8,6 +8,9 @@ import dev.meloda.fast.network.RestApiErrorDomain
|
||||
interface ConvosRepository {
|
||||
|
||||
suspend fun storeConvos(convos: List<VkConvo>)
|
||||
suspend fun getLocalConvos(): List<VkConvo>
|
||||
suspend fun getLocalConvoById(peerId: Long): VkConvo?
|
||||
suspend fun deleteLocalConvo(peerId: Long)
|
||||
|
||||
suspend fun getConvos(
|
||||
count: Int?,
|
||||
|
||||
@@ -19,11 +19,13 @@ import dev.meloda.fast.model.api.domain.VkGroupDomain
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import dev.meloda.fast.model.api.domain.asEntity
|
||||
import dev.meloda.fast.model.database.VkConvoEntity
|
||||
import dev.meloda.fast.model.api.requests.ConvosGetRequest
|
||||
import dev.meloda.fast.network.RestApiErrorDomain
|
||||
import dev.meloda.fast.network.mapApiDefault
|
||||
import dev.meloda.fast.network.mapApiResult
|
||||
import dev.meloda.fast.network.service.convos.ConvosService
|
||||
import dev.meloda.fast.model.database.asExternalModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -40,6 +42,28 @@ class ConvosRepositoryImpl(
|
||||
convoDao.insertAll(convos.map(VkConvo::asEntity))
|
||||
}
|
||||
|
||||
override suspend fun getLocalConvos(): List<VkConvo> = withContext(Dispatchers.IO) {
|
||||
convoDao.getAllWithMessage().map { convoWithMessage ->
|
||||
convoWithMessage.convo.asExternalModel().copy(
|
||||
lastMessage = convoWithMessage.message?.asExternalModel()
|
||||
)
|
||||
}.sorted()
|
||||
}
|
||||
|
||||
override suspend fun getLocalConvoById(peerId: Long): VkConvo? = withContext(Dispatchers.IO) {
|
||||
convoDao.getByIdWithMessage(peerId)?.let { convoWithMessage ->
|
||||
convoWithMessage.convo.asExternalModel().copy(
|
||||
lastMessage = convoWithMessage.message?.asExternalModel()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteLocalConvo(peerId: Long) {
|
||||
withContext(Dispatchers.IO) {
|
||||
convoDao.deleteById(peerId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getConvos(
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
@@ -198,4 +222,28 @@ class ConvosRepositoryImpl(
|
||||
): ApiResult<Int, RestApiErrorDomain> = withContext(Dispatchers.IO) {
|
||||
convosService.unarchive(mapOf("peer_id" to peerId.toString())).mapApiDefault()
|
||||
}
|
||||
|
||||
private fun List<VkConvo>.sorted(): List<VkConvo> {
|
||||
val newConvos = toMutableList()
|
||||
|
||||
val pinnedConvos = newConvos
|
||||
.filter(VkConvo::isPinned)
|
||||
.sortedWith { c1, c2 ->
|
||||
val diff = c2.majorId - c1.majorId
|
||||
|
||||
if (diff == 0) {
|
||||
c2.minorId - c1.minorId
|
||||
} else {
|
||||
diff
|
||||
}
|
||||
}
|
||||
|
||||
newConvos.removeAll(pinnedConvos)
|
||||
newConvos.sortWith { c1, c2 ->
|
||||
(c2.lastMessage?.date ?: 0) - (c1.lastMessage?.date ?: 0)
|
||||
}
|
||||
|
||||
newConvos.addAll(0, pinnedConvos)
|
||||
return newConvos
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.meloda.fast.data.api.longpoll
|
||||
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.LongPollHistoryResponse
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import dev.meloda.fast.network.RestApiErrorDomain
|
||||
import com.slack.eithernet.ApiResult
|
||||
@@ -21,4 +22,14 @@ interface LongPollRepository {
|
||||
mode: Int,
|
||||
version: Int
|
||||
): ApiResult<LongPollUpdates, RestApiErrorDomain>
|
||||
|
||||
suspend fun getLongPollHistory(
|
||||
ts: Int,
|
||||
pts: Int,
|
||||
lpVersion: Int,
|
||||
lastN: Int? = null,
|
||||
maxMsgId: Long? = null,
|
||||
eventsLimit: Int? = null,
|
||||
msgsLimit: Int? = null
|
||||
): ApiResult<LongPollHistoryResponse, RestApiErrorDomain>
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package dev.meloda.fast.data.api.longpoll
|
||||
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.LongPollHistoryResponse
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import dev.meloda.fast.model.api.requests.LongPollGetHistoryRequest
|
||||
import dev.meloda.fast.model.api.requests.LongPollGetUpdatesRequest
|
||||
import dev.meloda.fast.model.api.requests.MessagesGetLongPollServerRequest
|
||||
import dev.meloda.fast.network.RestApiErrorDomain
|
||||
@@ -52,4 +54,29 @@ class LongPollRepositoryImpl(
|
||||
|
||||
longPollService.getResponse(serverUrl, requestModel.map).mapDefault()
|
||||
}
|
||||
|
||||
override suspend fun getLongPollHistory(
|
||||
ts: Int,
|
||||
pts: Int,
|
||||
lpVersion: Int,
|
||||
lastN: Int?,
|
||||
maxMsgId: Long?,
|
||||
eventsLimit: Int?,
|
||||
msgsLimit: Int?
|
||||
): ApiResult<LongPollHistoryResponse, RestApiErrorDomain> = withContext(Dispatchers.IO) {
|
||||
val requestModel = LongPollGetHistoryRequest(
|
||||
ts = ts,
|
||||
pts = pts,
|
||||
lpVersion = lpVersion,
|
||||
lastN = lastN,
|
||||
maxMsgId = maxMsgId,
|
||||
eventsLimit = eventsLimit,
|
||||
msgsLimit = msgsLimit
|
||||
)
|
||||
|
||||
messagesService.getLongPollHistory(requestModel.map).mapApiResult(
|
||||
successMapper = { response -> response.requireResponse() },
|
||||
errorMapper = { error -> error?.toDomain() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ interface MessagesRepository {
|
||||
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
|
||||
suspend fun getLocalMessages(convoId: Long): List<VkMessage>
|
||||
suspend fun getLocalMessageById(messageId: Long): VkMessage?
|
||||
suspend fun getLocalMessageByConvoMessageId(convoId: Long, cmId: Long): VkMessage?
|
||||
suspend fun getLocalMaxMessageId(): Long?
|
||||
suspend fun deleteLocalMessages(messageIds: List<Long>)
|
||||
|
||||
suspend fun getHistory(
|
||||
convoId: Long,
|
||||
offset: Int?,
|
||||
|
||||
@@ -22,6 +22,7 @@ import dev.meloda.fast.model.api.domain.VkGroupDomain
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import dev.meloda.fast.model.api.domain.asEntity
|
||||
import dev.meloda.fast.model.database.VkMessageEntity
|
||||
import dev.meloda.fast.model.api.requests.MessagesCreateChatRequest
|
||||
import dev.meloda.fast.model.api.requests.MessagesDeleteRequest
|
||||
import dev.meloda.fast.model.api.requests.MessagesEditRequest
|
||||
@@ -39,6 +40,7 @@ import dev.meloda.fast.model.api.requests.MessagesUnpinMessageRequest
|
||||
import dev.meloda.fast.model.api.responses.MessagesGetConvoMembersResponse
|
||||
import dev.meloda.fast.model.api.responses.MessagesGetReadPeersResponse
|
||||
import dev.meloda.fast.model.api.responses.MessagesSendResponse
|
||||
import dev.meloda.fast.model.database.asExternalModel
|
||||
import dev.meloda.fast.network.RestApiErrorDomain
|
||||
import dev.meloda.fast.network.mapApiDefault
|
||||
import dev.meloda.fast.network.mapApiResult
|
||||
@@ -354,6 +356,28 @@ class MessagesRepositoryImpl(
|
||||
messageDao.insertAll(messages.map(VkMessage::asEntity))
|
||||
}
|
||||
|
||||
override suspend fun getLocalMessages(convoId: Long): List<VkMessage> = withContext(Dispatchers.IO) {
|
||||
messageDao.getAll(convoId).map(VkMessageEntity::asExternalModel)
|
||||
}
|
||||
|
||||
override suspend fun getLocalMessageById(messageId: Long): VkMessage? = withContext(Dispatchers.IO) {
|
||||
messageDao.getById(messageId)?.asExternalModel()
|
||||
}
|
||||
|
||||
override suspend fun getLocalMessageByConvoMessageId(convoId: Long, cmId: Long): VkMessage? = withContext(Dispatchers.IO) {
|
||||
messageDao.getByConvoMessageId(convoId, cmId)?.asExternalModel()
|
||||
}
|
||||
|
||||
override suspend fun getLocalMaxMessageId(): Long? = withContext(Dispatchers.IO) {
|
||||
messageDao.getMaxId()
|
||||
}
|
||||
|
||||
override suspend fun deleteLocalMessages(messageIds: List<Long>) {
|
||||
withContext(Dispatchers.IO) {
|
||||
messageDao.deleteByIds(messageIds)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun edit(
|
||||
peerId: Long,
|
||||
messageId: Long?,
|
||||
|
||||
@@ -9,9 +9,13 @@ import dev.meloda.fast.model.database.VkConvoEntity
|
||||
@Dao
|
||||
abstract class ConvoDao : EntityDao<VkConvoEntity> {
|
||||
|
||||
@Query("SELECT * FROM convos")
|
||||
@Query("SELECT * FROM convos ORDER BY majorId DESC, minorId DESC")
|
||||
abstract suspend fun getAll(): List<VkConvoEntity>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM convos ORDER BY majorId DESC, minorId DESC")
|
||||
abstract suspend fun getAllWithMessage(): List<ConvoWithMessage>
|
||||
|
||||
@Query("SELECT * FROM convos WHERE id IN (:ids)")
|
||||
abstract suspend fun getAllByIds(ids: List<Int>): List<VkConvoEntity>
|
||||
|
||||
@@ -22,6 +26,9 @@ abstract class ConvoDao : EntityDao<VkConvoEntity> {
|
||||
@Query("SELECT * FROM convos WHERE id IS (:id)")
|
||||
abstract suspend fun getByIdWithMessage(id: Long): ConvoWithMessage?
|
||||
|
||||
@Query("DELETE FROM convos WHERE id IS (:id)")
|
||||
abstract suspend fun deleteById(id: Long): Int
|
||||
|
||||
@Query("DELETE FROM convos WHERE rowid IN (:ids)")
|
||||
abstract suspend fun deleteByIds(ids: List<Int>): Int
|
||||
}
|
||||
|
||||
@@ -10,15 +10,21 @@ abstract class MessageDao : EntityDao<VkMessageEntity> {
|
||||
@Query("SELECT * FROM messages")
|
||||
abstract suspend fun getAll(): List<VkMessageEntity>
|
||||
|
||||
@Query("SELECT * FROM messages WHERE peerId IS (:convoId)")
|
||||
@Query("SELECT * FROM messages WHERE peerId IS (:convoId) ORDER BY date DESC, id DESC")
|
||||
abstract suspend fun getAll(convoId: Long): List<VkMessageEntity>
|
||||
|
||||
@Query("SELECT * FROM messages WHERE id IN (:ids)")
|
||||
abstract suspend fun getAllByIds(ids: List<Int>): List<VkMessageEntity>
|
||||
abstract suspend fun getAllByIds(ids: List<Long>): List<VkMessageEntity>
|
||||
|
||||
@Query("SELECT * FROM messages WHERE id IS (:messageId)")
|
||||
abstract suspend fun getById(messageId: Long): VkMessageEntity?
|
||||
|
||||
@Query("SELECT * FROM messages WHERE peerId IS (:convoId) AND cmId IS (:cmId)")
|
||||
abstract suspend fun getByConvoMessageId(convoId: Long, cmId: Long): VkMessageEntity?
|
||||
|
||||
@Query("SELECT MAX(id) FROM messages")
|
||||
abstract suspend fun getMaxId(): Long?
|
||||
|
||||
@Query("DELETE FROM messages WHERE id IN (:ids)")
|
||||
abstract suspend fun deleteByIds(ids: List<Int>): Int
|
||||
abstract suspend fun deleteByIds(ids: List<Long>): Int
|
||||
}
|
||||
|
||||
@@ -230,6 +230,21 @@ object AppSettings {
|
||||
set(value) = put(SettingsKeys.KEY_MORE_ANIMATIONS, value)
|
||||
}
|
||||
|
||||
object LongPoll {
|
||||
var ts: Int?
|
||||
get() = get(SettingsKeys.KEY_LONG_POLL_TS, 0).takeIf { it > 0 }
|
||||
set(value) = put(SettingsKeys.KEY_LONG_POLL_TS, value ?: 0)
|
||||
|
||||
var pts: Int?
|
||||
get() = get(SettingsKeys.KEY_LONG_POLL_PTS, 0).takeIf { it > 0 }
|
||||
set(value) = put(SettingsKeys.KEY_LONG_POLL_PTS, value ?: 0)
|
||||
|
||||
fun clear() {
|
||||
ts = null
|
||||
pts = null
|
||||
}
|
||||
}
|
||||
|
||||
object Debug {
|
||||
var showAlertAfterCrash: Boolean
|
||||
get() = get(
|
||||
|
||||
@@ -39,6 +39,8 @@ object SettingsKeys {
|
||||
const val DEFAULT_VALUE_FEATURES_FAST_TEXT = "¯\\_(ツ)_/¯"
|
||||
const val KEY_LONG_POLL_IN_BACKGROUND = "lp_background"
|
||||
const val DEFAULT_LONG_POLL_IN_BACKGROUND = false
|
||||
const val KEY_LONG_POLL_TS = "lp_ts"
|
||||
const val KEY_LONG_POLL_PTS = "lp_pts"
|
||||
|
||||
const val KEY_ACTIVITY_SEND_ONLINE_STATUS = "activity_send_online_status"
|
||||
const val DEFAULT_VALUE_KEY_ACTIVITY_SEND_ONLINE_STATUS = false
|
||||
|
||||
@@ -8,6 +8,9 @@ import kotlinx.coroutines.flow.Flow
|
||||
interface ConvoUseCase : BaseUseCase {
|
||||
|
||||
suspend fun storeConvos(convos: List<VkConvo>)
|
||||
suspend fun getLocalConvos(): List<VkConvo>
|
||||
suspend fun getLocalConvoById(peerId: Long): VkConvo?
|
||||
suspend fun deleteLocalConvo(peerId: Long)
|
||||
|
||||
fun getConvos(
|
||||
count: Int? = null,
|
||||
|
||||
@@ -19,6 +19,18 @@ class ConvoUseCaseImpl(
|
||||
repository.storeConvos(convos)
|
||||
}
|
||||
|
||||
override suspend fun getLocalConvos(): List<VkConvo> = withContext(Dispatchers.IO) {
|
||||
repository.getLocalConvos()
|
||||
}
|
||||
|
||||
override suspend fun getLocalConvoById(peerId: Long): VkConvo? = withContext(Dispatchers.IO) {
|
||||
repository.getLocalConvoById(peerId)
|
||||
}
|
||||
|
||||
override suspend fun deleteLocalConvo(peerId: Long) = withContext(Dispatchers.IO) {
|
||||
repository.deleteLocalConvo(peerId)
|
||||
}
|
||||
|
||||
override fun getConvos(
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
|
||||
@@ -66,6 +66,14 @@ class LongPollUpdatesParser(
|
||||
eventDispatcher.registerListener(LongPollEvent.MESSAGE_RESTORED, assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onMessageUpdated(block: (LongPollParsedEvent.MessageUpdated) -> Unit) {
|
||||
eventDispatcher.registerListener(LongPollEvent.MESSAGE_UPDATED, assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onMessageCacheClear(block: (LongPollParsedEvent.MessageCacheClear) -> Unit) {
|
||||
eventDispatcher.registerListener(LongPollEvent.MESSAGE_CACHE_CLEAR, assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onNewMessage(block: (LongPollParsedEvent.NewMessage) -> Unit) {
|
||||
eventDispatcher.registerListener(LongPollEvent.MESSAGE_NEW, assembleEventCallback(block))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.model.LongPollParsedEvent
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LongPollUpdatesReducer(
|
||||
updatesParser: LongPollUpdatesParser,
|
||||
private val messagesUseCase: MessagesUseCase,
|
||||
private val convoUseCase: ConvoUseCase
|
||||
) {
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||
|
||||
private val _events = MutableSharedFlow<LongPollParsedEvent>(extraBufferCapacity = 256)
|
||||
val events: SharedFlow<LongPollParsedEvent> = _events.asSharedFlow()
|
||||
|
||||
val newMessages = events.filterIsInstance<LongPollParsedEvent.NewMessage>()
|
||||
val messageEdited = events.filterIsInstance<LongPollParsedEvent.MessageEdited>()
|
||||
val messageIncomingRead = events.filterIsInstance<LongPollParsedEvent.IncomingMessageRead>()
|
||||
val messageOutgoingRead = events.filterIsInstance<LongPollParsedEvent.OutgoingMessageRead>()
|
||||
val messageDeleted = events.filterIsInstance<LongPollParsedEvent.MessageDeleted>()
|
||||
val messageRestored = events.filterIsInstance<LongPollParsedEvent.MessageRestored>()
|
||||
val messageMarkedAsImportant = events.filterIsInstance<LongPollParsedEvent.MessageMarkedAsImportant>()
|
||||
val messageMarkedAsSpam = events.filterIsInstance<LongPollParsedEvent.MessageMarkedAsSpam>()
|
||||
val messageMarkedAsNotSpam = events.filterIsInstance<LongPollParsedEvent.MessageMarkedAsNotSpam>()
|
||||
val interactions = events.filterIsInstance<LongPollParsedEvent.Interaction>()
|
||||
val chatMajorChanged = events.filterIsInstance<LongPollParsedEvent.ChatMajorChanged>()
|
||||
val chatMinorChanged = events.filterIsInstance<LongPollParsedEvent.ChatMinorChanged>()
|
||||
val chatCleared = events.filterIsInstance<LongPollParsedEvent.ChatCleared>()
|
||||
val chatArchived = events.filterIsInstance<LongPollParsedEvent.ChatArchived>()
|
||||
val messageUpdated = events.filterIsInstance<LongPollParsedEvent.MessageUpdated>()
|
||||
val messageCacheClear = events.filterIsInstance<LongPollParsedEvent.MessageCacheClear>()
|
||||
|
||||
init {
|
||||
updatesParser.onNewMessage { publish(it) }
|
||||
updatesParser.onMessageEdited { publish(it) }
|
||||
updatesParser.onMessageIncomingRead { publish(it) }
|
||||
updatesParser.onMessageOutgoingRead { publish(it) }
|
||||
updatesParser.onMessageDeleted { publish(it) }
|
||||
updatesParser.onMessageRestored { publish(it) }
|
||||
updatesParser.onMessageUpdated { publish(it) }
|
||||
updatesParser.onMessageCacheClear { publish(it) }
|
||||
updatesParser.onMessageMarkedAsImportant { publish(it) }
|
||||
updatesParser.onMessageMarkedAsSpam { publish(it) }
|
||||
updatesParser.onMessageMarkedAsNotSpam { publish(it) }
|
||||
updatesParser.onInteractions { publish(it) }
|
||||
updatesParser.onChatMajorChanged { publish(it) }
|
||||
updatesParser.onChatMinorChanged { publish(it) }
|
||||
updatesParser.onChatCleared { publish(it) }
|
||||
updatesParser.onChatArchived { publish(it) }
|
||||
}
|
||||
|
||||
private fun publish(event: LongPollParsedEvent) {
|
||||
scope.launch {
|
||||
runCatching { applyCommon(event) }
|
||||
.onFailure { throwable ->
|
||||
Log.e("LongPollUpdatesReducer", "applyCommon failed: $event", throwable)
|
||||
}
|
||||
_events.emit(event)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun applyCommon(event: LongPollParsedEvent) {
|
||||
when (event) {
|
||||
is LongPollParsedEvent.NewMessage -> {
|
||||
messagesUseCase.storeMessages(listOf(event.message))
|
||||
updateConvoForMessage(event.message, unreadIncrement = if (event.message.isOut) 0 else 1)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageEdited -> {
|
||||
messagesUseCase.storeMessage(event.message)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageUpdated -> {
|
||||
messagesUseCase.storeMessage(event.message)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageCacheClear -> {
|
||||
messagesUseCase.storeMessage(event.message)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.IncomingMessageRead -> {
|
||||
updateConvoReadState(
|
||||
peerId = event.peerId,
|
||||
inReadCmId = event.cmId,
|
||||
unreadCount = event.unreadCount
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.OutgoingMessageRead -> {
|
||||
updateConvoReadState(
|
||||
peerId = event.peerId,
|
||||
outReadCmId = event.cmId,
|
||||
unreadCount = event.unreadCount
|
||||
)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageDeleted -> {
|
||||
val message = messagesUseCase.getLocalMessageByConvoMessageId(
|
||||
convoId = event.peerId,
|
||||
cmId = event.cmId
|
||||
)
|
||||
if (message != null) {
|
||||
messagesUseCase.deleteLocalMessages(listOf(message.id))
|
||||
}
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageRestored -> {
|
||||
messagesUseCase.storeMessage(event.message)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageMarkedAsImportant -> {
|
||||
val message = messagesUseCase.getLocalMessageByConvoMessageId(
|
||||
convoId = event.peerId,
|
||||
cmId = event.cmId
|
||||
) ?: return
|
||||
|
||||
messagesUseCase.storeMessage(message.copy(isImportant = event.marked))
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageMarkedAsSpam -> {
|
||||
val message = messagesUseCase.getLocalMessageByConvoMessageId(
|
||||
convoId = event.peerId,
|
||||
cmId = event.cmId
|
||||
)
|
||||
if (message != null) {
|
||||
messagesUseCase.deleteLocalMessages(listOf(message.id))
|
||||
}
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.MessageMarkedAsNotSpam -> {
|
||||
messagesUseCase.storeMessage(event.message)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.ChatMajorChanged -> {
|
||||
updateConvoSortState(event.peerId, majorId = event.majorId)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.ChatMinorChanged -> {
|
||||
updateConvoSortState(event.peerId, minorId = event.minorId)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.ChatCleared -> {
|
||||
convoUseCase.deleteLocalConvo(event.peerId)
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.ChatArchived -> {
|
||||
event.convo.lastMessage?.let(messagesUseCase::storeMessage)
|
||||
convoUseCase.storeConvos(listOf(event.convo.copy(isArchived = event.archived)))
|
||||
}
|
||||
|
||||
is LongPollParsedEvent.Interaction -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateConvoReadState(
|
||||
peerId: Long,
|
||||
inReadCmId: Long? = null,
|
||||
outReadCmId: Long? = null,
|
||||
unreadCount: Int
|
||||
) {
|
||||
val convo = convoUseCase.getLocalConvoById(peerId) ?: return
|
||||
convoUseCase.storeConvos(
|
||||
listOf(
|
||||
convo.copy(
|
||||
inReadCmId = inReadCmId ?: convo.inReadCmId,
|
||||
outReadCmId = outReadCmId ?: convo.outReadCmId,
|
||||
unreadCount = unreadCount
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateConvoSortState(
|
||||
peerId: Long,
|
||||
majorId: Int? = null,
|
||||
minorId: Int? = null
|
||||
) {
|
||||
val convo = convoUseCase.getLocalConvoById(peerId) ?: return
|
||||
convoUseCase.storeConvos(
|
||||
listOf(
|
||||
convo.copy(
|
||||
majorId = majorId ?: convo.majorId,
|
||||
minorId = minorId ?: convo.minorId
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateConvoForMessage(
|
||||
message: VkMessage,
|
||||
unreadIncrement: Int
|
||||
) {
|
||||
val convo = convoUseCase.getLocalConvoById(message.peerId) ?: return
|
||||
convoUseCase.storeConvos(
|
||||
listOf(
|
||||
convo.copy(
|
||||
lastMessageId = message.id,
|
||||
lastCmId = message.cmId,
|
||||
unreadCount = convo.unreadCount + unreadIncrement
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.model.api.data.LongPollHistoryResponse
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -21,4 +22,14 @@ interface LongPollUseCase {
|
||||
mode: Int,
|
||||
version: Int
|
||||
): Flow<State<LongPollUpdates>>
|
||||
|
||||
fun getLongPollHistory(
|
||||
ts: Int,
|
||||
pts: Int,
|
||||
lpVersion: Int,
|
||||
lastN: Int? = null,
|
||||
maxMsgId: Long? = null,
|
||||
eventsLimit: Int? = null,
|
||||
msgsLimit: Int? = null
|
||||
): Flow<State<LongPollHistoryResponse>>
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.meloda.fast.domain
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.api.longpoll.LongPollRepository
|
||||
import dev.meloda.fast.data.mapToState
|
||||
import dev.meloda.fast.model.api.data.LongPollHistoryResponse
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -48,4 +49,27 @@ class LongPollUseCaseImpl(
|
||||
).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun getLongPollHistory(
|
||||
ts: Int,
|
||||
pts: Int,
|
||||
lpVersion: Int,
|
||||
lastN: Int?,
|
||||
maxMsgId: Long?,
|
||||
eventsLimit: Int?,
|
||||
msgsLimit: Int?
|
||||
): Flow<State<LongPollHistoryResponse>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getLongPollHistory(
|
||||
ts = ts,
|
||||
pts = pts,
|
||||
lpVersion = lpVersion,
|
||||
lastN = lastN,
|
||||
maxMsgId = maxMsgId,
|
||||
eventsLimit = eventsLimit,
|
||||
msgsLimit = msgsLimit
|
||||
).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@ interface MessagesUseCase : BaseUseCase {
|
||||
|
||||
suspend fun storeMessage(message: VkMessage)
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
suspend fun getLocalMessages(convoId: Long): List<VkMessage>
|
||||
suspend fun getLocalMessageById(messageId: Long): VkMessage?
|
||||
suspend fun getLocalMessageByConvoMessageId(convoId: Long, cmId: Long): VkMessage?
|
||||
suspend fun getLocalMaxMessageId(): Long?
|
||||
suspend fun deleteLocalMessages(messageIds: List<Long>)
|
||||
|
||||
fun getMessagesHistory(
|
||||
convoId: Long,
|
||||
|
||||
@@ -22,6 +22,26 @@ class MessagesUseCaseImpl(
|
||||
repository.storeMessages(messages)
|
||||
}
|
||||
|
||||
override suspend fun getLocalMessages(convoId: Long): List<VkMessage> {
|
||||
return repository.getLocalMessages(convoId)
|
||||
}
|
||||
|
||||
override suspend fun getLocalMessageById(messageId: Long): VkMessage? {
|
||||
return repository.getLocalMessageById(messageId)
|
||||
}
|
||||
|
||||
override suspend fun getLocalMessageByConvoMessageId(convoId: Long, cmId: Long): VkMessage? {
|
||||
return repository.getLocalMessageByConvoMessageId(convoId, cmId)
|
||||
}
|
||||
|
||||
override suspend fun getLocalMaxMessageId(): Long? {
|
||||
return repository.getLocalMaxMessageId()
|
||||
}
|
||||
|
||||
override suspend fun deleteLocalMessages(messageIds: List<Long>) {
|
||||
repository.deleteLocalMessages(messageIds)
|
||||
}
|
||||
|
||||
override fun getMessagesHistory(
|
||||
convoId: Long,
|
||||
count: Int?,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.meloda.fast.model.api.data
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class LongPollHistoryResponse(
|
||||
@Json(name = "history") val history: List<List<Any>>? = null,
|
||||
@Json(name = "messages") val messages: Messages? = null,
|
||||
@Json(name = "profiles") val profiles: List<VkUserData>? = null,
|
||||
@Json(name = "groups") val groups: List<VkGroupData>? = null,
|
||||
@Json(name = "new_pts") val newPts: Int? = null,
|
||||
@Json(name = "from_pts") val fromPts: Int? = null,
|
||||
@Json(name = "ts") val ts: Int? = null,
|
||||
@Json(name = "pts") val pts: Int? = null,
|
||||
@Json(name = "more") val more: Int? = null,
|
||||
@Json(name = "conversations") val conversations: List<VkConvoData>? = null
|
||||
) {
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Messages(
|
||||
@Json(name = "count") val count: Int? = null,
|
||||
@Json(name = "items") val items: List<VkMessageData>? = null
|
||||
)
|
||||
}
|
||||
@@ -19,3 +19,27 @@ data class LongPollGetUpdatesRequest(
|
||||
"version" to version.toString()
|
||||
)
|
||||
}
|
||||
|
||||
data class LongPollGetHistoryRequest(
|
||||
val ts: Int,
|
||||
val pts: Int,
|
||||
val lpVersion: Int,
|
||||
val lastN: Int? = null,
|
||||
val maxMsgId: Long? = null,
|
||||
val eventsLimit: Int? = null,
|
||||
val msgsLimit: Int? = null,
|
||||
val extended: Boolean = true,
|
||||
) {
|
||||
val map: Map<String, String>
|
||||
get() = mutableMapOf(
|
||||
"ts" to ts.toString(),
|
||||
"pts" to pts.toString(),
|
||||
"lp_version" to lpVersion.toString(),
|
||||
"extended" to if (extended) "1" else "0",
|
||||
).apply {
|
||||
lastN?.let { this["last_n"] = it.toString() }
|
||||
maxMsgId?.let { this["max_msg_id"] = it.toString() }
|
||||
eventsLimit?.let { this["events_limit"] = it.toString() }
|
||||
msgsLimit?.let { this["msgs_limit"] = it.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -2,6 +2,7 @@ package dev.meloda.fast.network.service.messages
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import dev.meloda.fast.model.api.data.VkChatData
|
||||
import dev.meloda.fast.model.api.data.LongPollHistoryResponse
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import dev.meloda.fast.model.api.data.VkMessageData
|
||||
import dev.meloda.fast.model.api.responses.MessagesCreateChatResponse
|
||||
@@ -44,6 +45,12 @@ interface MessagesService {
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<VkLongPollData>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.GET_LONG_POLL_HISTORY)
|
||||
suspend fun getLongPollHistory(
|
||||
@FieldMap params: Map<String, String>
|
||||
): ApiResult<ApiResponse<LongPollHistoryResponse>, RestApiError>
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(MessagesUrls.MARK_AS_READ)
|
||||
suspend fun markAsRead(
|
||||
|
||||
Reference in New Issue
Block a user