Update API version (#147)
* Bump VK Api version to 5.238 * Implemented new authorization flow (at the moment, without auto re-requesting token) * Add support for sticker pack preview attachments * Bump LongPoll to version 19 * Improved messages handling * Fixed coloring issues * Cache improvements * Archive screen with full functionality * Recomposition fixes * Markdown support for messages bubbles * Adjust app name font size based on screen width * Navigation related improvements * Add logout functionality
This commit is contained in:
@@ -1,12 +1,32 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.model.api.responses.ExchangeSilentTokenResponse
|
||||
import dev.meloda.fast.model.api.responses.GetAnonymTokenResponse
|
||||
import dev.meloda.fast.model.api.responses.GetExchangeTokenResponse
|
||||
import dev.meloda.fast.model.api.responses.ValidatePhoneResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AuthUseCase {
|
||||
interface AuthUseCase : BaseUseCase {
|
||||
|
||||
fun logout(): Flow<State<Int>>
|
||||
|
||||
fun validatePhone(
|
||||
validationSid: String
|
||||
): Flow<State<ValidatePhoneResponse>>
|
||||
|
||||
suspend fun getAnonymToken(
|
||||
clientId: String,
|
||||
clientSecret: String
|
||||
): Flow<State<GetAnonymTokenResponse>>
|
||||
|
||||
suspend fun exchangeSilentToken(
|
||||
anonymToken: String,
|
||||
silentToken: String,
|
||||
silentUuid: String
|
||||
): Flow<State<ExchangeSilentTokenResponse>>
|
||||
|
||||
suspend fun getExchangeToken(
|
||||
accessToken: String
|
||||
): Flow<State<GetExchangeTokenResponse>>
|
||||
}
|
||||
|
||||
@@ -3,16 +3,44 @@ package dev.meloda.fast.domain
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.api.auth.AuthRepository
|
||||
import dev.meloda.fast.data.mapToState
|
||||
import dev.meloda.fast.model.api.responses.ExchangeSilentTokenResponse
|
||||
import dev.meloda.fast.model.api.responses.GetAnonymTokenResponse
|
||||
import dev.meloda.fast.model.api.responses.GetExchangeTokenResponse
|
||||
import dev.meloda.fast.model.api.responses.ValidatePhoneResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class AuthUseCaseImpl(private val repository: AuthRepository) : AuthUseCase {
|
||||
|
||||
override fun validatePhone(validationSid: String): Flow<State<ValidatePhoneResponse>> = flow {
|
||||
emit(State.Loading)
|
||||
override fun logout(): Flow<State<Int>> = flowNewState { repository.logout().mapToState() }
|
||||
|
||||
val newState = repository.validatePhone(validationSid).mapToState()
|
||||
emit(newState)
|
||||
override fun validatePhone(validationSid: String): Flow<State<ValidatePhoneResponse>> =
|
||||
flowNewState { repository.validatePhone(validationSid = validationSid).mapToState() }
|
||||
|
||||
override suspend fun getAnonymToken(
|
||||
clientId: String,
|
||||
clientSecret: String
|
||||
): Flow<State<GetAnonymTokenResponse>> = flowNewState {
|
||||
repository.getAnonymToken(
|
||||
clientId = clientId,
|
||||
clientSecret = clientSecret
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override suspend fun exchangeSilentToken(
|
||||
anonymToken: String,
|
||||
silentToken: String,
|
||||
silentUuid: String
|
||||
): Flow<State<ExchangeSilentTokenResponse>> = flowNewState {
|
||||
repository.exchangeSilentToken(
|
||||
anonymToken = anonymToken,
|
||||
silentToken = silentToken,
|
||||
silentUuid = silentUuid
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override suspend fun getExchangeToken(
|
||||
accessToken: String
|
||||
): Flow<State<GetExchangeTokenResponse>> = flowNewState {
|
||||
repository.getExchangeToken(accessToken = accessToken).mapToState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
interface BaseUseCase {
|
||||
|
||||
suspend fun <T> FlowCollector<State<T>>.emitState(stateBlock: suspend () -> State<T>) {
|
||||
emit(State.Loading)
|
||||
emit(stateBlock())
|
||||
}
|
||||
|
||||
fun <T> flowNewState(stateBlock: suspend () -> State<T>) =
|
||||
flow { emitState(stateBlock) }
|
||||
}
|
||||
@@ -1,19 +1,29 @@
|
||||
package dev.meloda.fast.domain
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.model.ConversationsFilter
|
||||
import dev.meloda.fast.model.api.domain.VkConversation
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface ConversationsUseCase {
|
||||
|
||||
fun getConversations(
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
): Flow<State<List<VkConversation>>>
|
||||
|
||||
fun delete(peerId: Int): Flow<State<Int>>
|
||||
|
||||
fun changePinState(peerId: Int, pin: Boolean): Flow<State<Int>>
|
||||
interface ConversationsUseCase : BaseUseCase {
|
||||
|
||||
suspend fun storeConversations(conversations: List<VkConversation>)
|
||||
|
||||
fun getConversations(
|
||||
count: Int? = null,
|
||||
offset: Int? = null,
|
||||
filter: ConversationsFilter
|
||||
): Flow<State<List<VkConversation>>>
|
||||
|
||||
fun getById(
|
||||
peerIds: List<Long>,
|
||||
extended: Boolean? = null,
|
||||
fields: String? = null
|
||||
): Flow<State<List<VkConversation>>>
|
||||
|
||||
fun delete(peerId: Long): Flow<State<Long>>
|
||||
|
||||
fun changePinState(peerId: Long, pin: Boolean): Flow<State<Int>>
|
||||
|
||||
fun changeArchivedState(peerId: Long, archive: Boolean): Flow<State<Int>>
|
||||
}
|
||||
|
||||
@@ -3,116 +3,69 @@ package dev.meloda.fast.domain
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.api.conversations.ConversationsRepository
|
||||
import dev.meloda.fast.data.mapToState
|
||||
import dev.meloda.fast.model.ConversationsFilter
|
||||
import dev.meloda.fast.model.api.domain.VkConversation
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ConversationsUseCaseImpl(
|
||||
private val repository: ConversationsRepository,
|
||||
) : ConversationsUseCase {
|
||||
|
||||
// override fun getConversations(
|
||||
// count: Int?,
|
||||
// offset: Int?,
|
||||
// fields: String,
|
||||
// filter: String,
|
||||
// extended: Boolean?,
|
||||
// startMessageId: Int?
|
||||
// ): Flow<dev.meloda.fast.network.State<ConversationsResponseDomain>> = flow {
|
||||
// emit(dev.meloda.fast.network.State.Loading)
|
||||
//
|
||||
// val newState = conversationsRepository.getConversations(
|
||||
// params = ConversationsGetRequest(
|
||||
// count = count,
|
||||
// offset = offset,
|
||||
// fields = fields,
|
||||
// filter = filter,
|
||||
// extended = extended,
|
||||
// startMessageId = startMessageId
|
||||
// )
|
||||
// ).fold(
|
||||
// onSuccess = { response -> dev.meloda.fast.network.State.Success(response.toDomain()) },
|
||||
// onNetworkFailure = { dev.meloda.fast.network.State.Error.ConnectionError },
|
||||
// onUnknownFailure = { dev.meloda.fast.network.State.UNKNOWN_ERROR },
|
||||
// onHttpFailure = { result -> result.error.toStateApiError() },
|
||||
// onApiFailure = { result -> result.error.toStateApiError() }
|
||||
// )
|
||||
// emit(newState)
|
||||
// }
|
||||
//
|
||||
|
||||
//
|
||||
// override fun pin(peerId: Int): Flow<dev.meloda.fast.network.State<Unit>> = flow {
|
||||
// emit(dev.meloda.fast.network.State.Loading)
|
||||
//
|
||||
// val newState = conversationsRepository.pin(
|
||||
// ConversationsPinRequest(peerId = peerId)
|
||||
// ).fold(
|
||||
// onSuccess = { dev.meloda.fast.network.State.Success(Unit) },
|
||||
// onNetworkFailure = { dev.meloda.fast.network.State.Error.ConnectionError },
|
||||
// onUnknownFailure = { dev.meloda.fast.network.State.UNKNOWN_ERROR },
|
||||
// onHttpFailure = { result -> result.error.toStateApiError() },
|
||||
// onApiFailure = { result -> result.error.toStateApiError() }
|
||||
// )
|
||||
// emit(newState)
|
||||
// }
|
||||
//
|
||||
// override fun unpin(peerId: Int): Flow<dev.meloda.fast.network.State<Unit>> = flow {
|
||||
// emit(dev.meloda.fast.network.State.Loading)
|
||||
//
|
||||
// val newState = conversationsRepository.unpin(
|
||||
// ConversationsUnpinRequest(peerId = peerId)
|
||||
// ).fold(
|
||||
// onSuccess = { dev.meloda.fast.network.State.Success(Unit) },
|
||||
// onNetworkFailure = { dev.meloda.fast.network.State.Error.ConnectionError },
|
||||
// onUnknownFailure = { dev.meloda.fast.network.State.UNKNOWN_ERROR },
|
||||
// onHttpFailure = { result -> result.error.toStateApiError() },
|
||||
// onApiFailure = { result -> result.error.toStateApiError() }
|
||||
// )
|
||||
// emit(newState)
|
||||
// }
|
||||
//
|
||||
// override suspend fun storeConversations(conversations: List<VkConversationDomain>) {
|
||||
// conversationsDao.insertAll(conversations.map(VkConversationDomain::mapToDb))
|
||||
// }
|
||||
//
|
||||
// override suspend fun storeGroups(groups: List<VkGroupDomain>) {
|
||||
// groupsDao.insertAll(groups.map(VkGroupDomain::mapToDB))
|
||||
// }
|
||||
override fun getConversations(
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<List<VkConversation>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getConversations(count, offset).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun storeConversations(
|
||||
conversations: List<VkConversation>
|
||||
) = withContext(Dispatchers.IO) {
|
||||
repository.storeConversations(conversations)
|
||||
}
|
||||
|
||||
override fun delete(peerId: Int): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.delete(peerId = peerId).mapToState()
|
||||
emit(newState)
|
||||
override fun getConversations(
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
filter: ConversationsFilter
|
||||
): Flow<State<List<VkConversation>>> = flowNewState {
|
||||
repository.getConversations(
|
||||
count = count,
|
||||
offset = offset,
|
||||
filter = filter
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun changePinState(peerId: Int, pin: Boolean): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
override fun getById(
|
||||
peerIds: List<Long>,
|
||||
extended: Boolean?,
|
||||
fields: String?
|
||||
): Flow<State<List<VkConversation>>> = flowNewState {
|
||||
repository.getConversationsById(
|
||||
peerIds = peerIds,
|
||||
extended = extended,
|
||||
fields = fields
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
val newState = if (pin) {
|
||||
override fun delete(peerId: Long): Flow<State<Long>> = flowNewState {
|
||||
repository.delete(peerId = peerId).mapToState()
|
||||
}
|
||||
|
||||
override fun changePinState(
|
||||
peerId: Long,
|
||||
pin: Boolean
|
||||
): Flow<State<Int>> = flowNewState {
|
||||
if (pin) {
|
||||
repository.pin(peerId)
|
||||
} else {
|
||||
repository.unpin(peerId)
|
||||
}.mapToState()
|
||||
}
|
||||
|
||||
emit(newState)
|
||||
override fun changeArchivedState(
|
||||
peerId: Long,
|
||||
archive: Boolean
|
||||
): Flow<State<Int>> = flowNewState {
|
||||
if (archive) {
|
||||
repository.archive(peerId)
|
||||
} else {
|
||||
repository.unarchive(peerId)
|
||||
}.mapToState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ interface FriendsUseCase {
|
||||
fun getOnlineFriends(
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<List<Int>>>
|
||||
): Flow<State<List<Long>>>
|
||||
|
||||
suspend fun storeUsers(users: List<VkUser>)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class FriendsUseCaseImpl(private val repository: FriendsRepository) :
|
||||
|
||||
override fun getOnlineFriends(
|
||||
count: Int?, offset: Int?
|
||||
): Flow<State<List<Int>>> = flow {
|
||||
): Flow<State<List<Long>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getOnlineFriends(count, offset).mapToState()
|
||||
|
||||
@@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.flow
|
||||
|
||||
class GetLocalUserByIdUseCase(private val repository: UsersRepository) {
|
||||
|
||||
operator fun invoke(userId: Int): Flow<State<VkUser?>> = flow {
|
||||
operator fun invoke(userId: Long): Flow<State<VkUser?>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = kotlin.runCatching {
|
||||
@@ -21,7 +21,7 @@ class GetLocalUserByIdUseCase(private val repository: UsersRepository) {
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
suspend fun proceed(userId: Int): VkUser? {
|
||||
suspend fun proceed(userId: Long): VkUser? {
|
||||
return repository.getLocalUsers(userIds = listOf(userId)).singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.flow
|
||||
|
||||
class GetLocalUsersByIdsUseCase(private val repository: UsersRepository) {
|
||||
|
||||
operator fun invoke(userIds: List<Int>): Flow<State<List<VkUser>>> = flow {
|
||||
operator fun invoke(userIds: List<Long>): Flow<State<List<VkUser>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = kotlin.runCatching {
|
||||
|
||||
+12
-10
@@ -5,19 +5,21 @@ import dev.meloda.fast.data.api.conversations.ConversationsRepository
|
||||
import dev.meloda.fast.data.mapToState
|
||||
import dev.meloda.fast.model.api.domain.VkConversation
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class LoadConversationsByIdUseCase(
|
||||
private val conversationsRepository: ConversationsRepository
|
||||
) {
|
||||
) : BaseUseCase {
|
||||
|
||||
operator fun invoke(peerIds: List<Int>): Flow<State<List<VkConversation>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = conversationsRepository
|
||||
.getConversationsById(peerIds = peerIds)
|
||||
.mapToState()
|
||||
|
||||
emit(newState)
|
||||
operator fun invoke(
|
||||
peerIds: List<Long>,
|
||||
extended: Boolean? = null,
|
||||
fields: String? = null
|
||||
): Flow<State<List<VkConversation>>> = flowNewState {
|
||||
conversationsRepository
|
||||
.getConversationsById(
|
||||
peerIds = peerIds,
|
||||
extended = extended,
|
||||
fields = fields,
|
||||
).mapToState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.flow
|
||||
class LoadUserByIdUseCase(private val repository: UsersRepository) {
|
||||
|
||||
operator fun invoke(
|
||||
userId: Int?,
|
||||
userId: Long?,
|
||||
fields: String = VkConstants.USER_FIELDS,
|
||||
nomCase: String? = null
|
||||
): Flow<State<VkUser?>> = flow {
|
||||
|
||||
@@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.flow
|
||||
class LoadUsersByIdsUseCase(private val repository: UsersRepository) {
|
||||
|
||||
operator fun invoke(
|
||||
userIds: List<Int>?,
|
||||
userIds: List<Long>?,
|
||||
fields: String = VkConstants.USER_FIELDS,
|
||||
nomCase: String? = null
|
||||
): Flow<State<List<VkUser>>> = flow {
|
||||
|
||||
@@ -3,21 +3,24 @@ package dev.meloda.fast.domain
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.common.VkConstants
|
||||
import dev.meloda.fast.common.extensions.asInt
|
||||
import dev.meloda.fast.common.extensions.asLong
|
||||
import dev.meloda.fast.common.extensions.listenValue
|
||||
import dev.meloda.fast.common.extensions.toList
|
||||
import dev.meloda.fast.data.UserConfig
|
||||
import dev.meloda.fast.data.VkMemoryCache
|
||||
import dev.meloda.fast.data.processState
|
||||
import dev.meloda.fast.model.ApiEvent
|
||||
import dev.meloda.fast.model.ConversationFlags
|
||||
import dev.meloda.fast.model.InteractionType
|
||||
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.VkConversation
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
@@ -25,6 +28,7 @@ import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class LongPollUpdatesParser(
|
||||
private val conversationsUseCase: ConversationsUseCase,
|
||||
private val messagesUseCase: MessagesUseCase
|
||||
) {
|
||||
private val job = SupervisorJob()
|
||||
@@ -68,6 +72,458 @@ class LongPollUpdatesParser(
|
||||
ApiEvent.FILE_UPLOADING -> parseInteraction(eventType, event)
|
||||
|
||||
ApiEvent.UNREAD_COUNT_UPDATE -> parseUnreadCounterUpdate(eventType, event)
|
||||
ApiEvent.MESSAGE_UPDATED -> parseMessageUpdated(eventType, event)
|
||||
ApiEvent.MESSAGE_CACHE_CLEAR -> parseMessageCacheClear(eventType, event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageSetFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
val peerId = event[3].asLong()
|
||||
|
||||
val eventsToSend = mutableListOf<LongPollParsedEvent>()
|
||||
|
||||
val parsedFlags = MessageFlags.parse(flags)
|
||||
parsedFlags.forEach { flag ->
|
||||
when (flag) {
|
||||
MessageFlags.IMPORTANT -> {
|
||||
val eventToSend = LongPollParsedEvent.MessageMarkedAsImportant(
|
||||
peerId = peerId,
|
||||
cmId = cmId,
|
||||
marked = true
|
||||
)
|
||||
eventsToSend += eventToSend
|
||||
|
||||
listenersMap[LongPollEvent.MARKED_AS_IMPORTANT]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageMarkedAsImportant>)
|
||||
?.onEvent(eventToSend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageFlags.SPAM -> {
|
||||
val eventToSend = LongPollParsedEvent.MessageMarkedAsSpam(
|
||||
peerId = peerId,
|
||||
cmId = cmId
|
||||
)
|
||||
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)) {
|
||||
LongPollParsedEvent.MessageDeleted(
|
||||
peerId = peerId,
|
||||
cmId = cmId,
|
||||
forAll = true
|
||||
)
|
||||
} else {
|
||||
LongPollParsedEvent.MessageDeleted(
|
||||
peerId = peerId,
|
||||
cmId = cmId,
|
||||
forAll = false
|
||||
)
|
||||
}
|
||||
eventsToSend += eventToSend
|
||||
|
||||
listenersMap[LongPollEvent.MESSAGE_DELETED]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.MessageDeleted>)
|
||||
?.onEvent(eventToSend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageFlags.AUDIO_LISTENED -> {
|
||||
val eventToSend = LongPollParsedEvent.AudioMessageListened(
|
||||
peerId = peerId,
|
||||
cmId = cmId
|
||||
)
|
||||
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>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
val peerId = event[3].asLong()
|
||||
|
||||
val eventsToSend = mutableListOf<LongPollParsedEvent>()
|
||||
|
||||
val parsedFlags = MessageFlags.parse(flags)
|
||||
|
||||
coroutineScope.launch {
|
||||
parsedFlags.forEach { flag ->
|
||||
when (flag) {
|
||||
MessageFlags.IMPORTANT -> {
|
||||
val eventToSend = LongPollParsedEvent.MessageMarkedAsImportant(
|
||||
peerId = peerId,
|
||||
cmId = cmId,
|
||||
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)) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val message = loadMessage(
|
||||
peerId = peerId,
|
||||
cmId = cmId
|
||||
)
|
||||
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 -> {
|
||||
withContext(Dispatchers.IO) {
|
||||
val message = loadMessage(
|
||||
peerId = peerId,
|
||||
cmId = cmId
|
||||
)
|
||||
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>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val peerId = event[4].asLong()
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
val message =
|
||||
async { loadMessage(peerId = peerId, cmId = cmId) }.await()
|
||||
|
||||
val conversation =
|
||||
async {
|
||||
loadConversation(
|
||||
peerId = peerId,
|
||||
extended = true,
|
||||
fields = VkConstants.ALL_FIELDS
|
||||
)
|
||||
}.await()
|
||||
|
||||
message?.let {
|
||||
listenersMap[LongPollEvent.MESSAGE_NEW]?.let {
|
||||
it.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.NewMessage>)
|
||||
.onEvent(
|
||||
LongPollParsedEvent.NewMessage(
|
||||
message = message,
|
||||
inArchive = conversation?.isArchived == true
|
||||
// TODO: 03-Apr-25, Danil Nikolaev:
|
||||
// load user settings about restoring chats with
|
||||
// enabled notifications from archive
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageEdit(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val cmId = event[1].asLong()
|
||||
val peerId = event[3].asLong()
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
loadMessage(
|
||||
peerId = peerId,
|
||||
cmId = cmId
|
||||
)?.let { message ->
|
||||
listenersMap[LongPollEvent.MESSAGE_EDITED]?.let {
|
||||
it.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.MessageEdited>)
|
||||
.onEvent(LongPollParsedEvent.MessageEdited(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageReadIncoming(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val peerId = event[1].asLong()
|
||||
val cmId = event[2].asLong()
|
||||
val unreadCount = event[3].asInt()
|
||||
|
||||
listenersMap[LongPollEvent.INCOMING_MESSAGE_READ]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.IncomingMessageRead>)
|
||||
.onEvent(
|
||||
LongPollParsedEvent.IncomingMessageRead(
|
||||
peerId = peerId,
|
||||
cmId = cmId,
|
||||
unreadCount = unreadCount
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageReadOutgoing(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val peerId = event[1].asLong()
|
||||
val cmId = event[2].asLong()
|
||||
val unreadCount = event[3].asInt()
|
||||
|
||||
listenersMap[LongPollEvent.OUTGOING_MESSAGE_READ]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.OutgoingMessageRead>)
|
||||
.onEvent(
|
||||
LongPollParsedEvent.OutgoingMessageRead(
|
||||
peerId = peerId,
|
||||
cmId = cmId,
|
||||
unreadCount = unreadCount
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChatClearFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
|
||||
val eventsToSend = mutableListOf<LongPollParsedEvent>()
|
||||
|
||||
val parsedFlags = ConversationFlags.parse(flags)
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
parsedFlags.forEach { flag ->
|
||||
when (flag) {
|
||||
ConversationFlags.ARCHIVED -> {
|
||||
val conversation = loadConversation(
|
||||
peerId = peerId,
|
||||
extended = true,
|
||||
fields = VkConstants.ALL_FIELDS
|
||||
) ?: return@forEach
|
||||
|
||||
val message = loadMessage(
|
||||
peerId = peerId,
|
||||
cmId = conversation.lastCmId
|
||||
)
|
||||
|
||||
val eventToSend = LongPollParsedEvent.ChatArchived(
|
||||
conversation = conversation.copy(lastMessage = message),
|
||||
archived = false
|
||||
)
|
||||
eventsToSend += eventToSend
|
||||
|
||||
listenersMap[LongPollEvent.CHAT_ARCHIVED]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.ChatArchived>)
|
||||
?.onEvent(eventToSend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
eventsToSend.forEach { eventToSend ->
|
||||
listenersMap[LongPollEvent.CHAT_CLEAR_FLAGS]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as? VkEventCallback<LongPollParsedEvent>)?.onEvent(
|
||||
eventToSend
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChatSetFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val flags = event[2].asInt()
|
||||
|
||||
val eventsToSend = mutableListOf<LongPollParsedEvent>()
|
||||
|
||||
val parsedFlags = ConversationFlags.parse(flags)
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
parsedFlags.forEach { flag ->
|
||||
when (flag) {
|
||||
ConversationFlags.ARCHIVED -> {
|
||||
val conversation = loadConversation(
|
||||
peerId = peerId,
|
||||
extended = true,
|
||||
fields = VkConstants.ALL_FIELDS
|
||||
) ?: return@forEach
|
||||
|
||||
val message = loadMessage(
|
||||
peerId = peerId,
|
||||
cmId = conversation.lastCmId
|
||||
)
|
||||
|
||||
val eventToSend = LongPollParsedEvent.ChatArchived(
|
||||
conversation = conversation.copy(lastMessage = message),
|
||||
archived = true
|
||||
)
|
||||
eventsToSend += eventToSend
|
||||
|
||||
listenersMap[LongPollEvent.CHAT_ARCHIVED]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as? VkEventCallback<LongPollParsedEvent.ChatArchived>)
|
||||
?.onEvent(eventToSend)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
eventsToSend.forEach { eventToSend ->
|
||||
listenersMap[LongPollEvent.CHAT_SET_FLAGS]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as? VkEventCallback<LongPollParsedEvent>)?.onEvent(
|
||||
eventToSend
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessagesDeleted(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
val cmId = event[2].asLong()
|
||||
|
||||
listenersMap[LongPollEvent.CHAT_CLEARED]?.let { listeners ->
|
||||
listeners.forEach { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.ChatCleared>)
|
||||
.onEvent(
|
||||
LongPollParsedEvent.ChatCleared(
|
||||
peerId = peerId,
|
||||
toCmId = cmId
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChatMajorChanged(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val peerId = event[1].asLong()
|
||||
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].asLong()
|
||||
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,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +548,8 @@ class LongPollUpdatesParser(
|
||||
else -> return
|
||||
}
|
||||
|
||||
val peerId = event[1].asInt()
|
||||
val userIds = event[2].toList(Any::asInt).filter { it != UserConfig.userId }
|
||||
val peerId = event[1].asLong()
|
||||
val userIds = event[2].toList(Any::asLong).filter { it != UserConfig.userId }
|
||||
val totalCount = event[3].asInt()
|
||||
val timestamp = event[4].asInt()
|
||||
|
||||
@@ -145,325 +601,57 @@ class LongPollUpdatesParser(
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageSetFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
private fun parseMessageUpdated(eventType: ApiEvent, event: List<Any>) {
|
||||
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>) {
|
||||
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>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val messageId = event[1].asInt()
|
||||
val cmId = event[1].asLong()
|
||||
val peerId = event[4].asLong()
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
loadMessage(messageId)?.let { message ->
|
||||
listenersMap[LongPollEvent.MESSAGE_NEW]?.let {
|
||||
loadMessage(
|
||||
peerId = peerId,
|
||||
cmId = cmId
|
||||
)?.let { message ->
|
||||
listenersMap[LongPollEvent.MESSAGE_UPDATED]?.let {
|
||||
it.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.NewMessage>)
|
||||
.onEvent(LongPollParsedEvent.NewMessage(message))
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.MessageUpdated>)
|
||||
.onEvent(LongPollParsedEvent.MessageUpdated(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageEdit(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val messageId = event[1].asInt()
|
||||
private fun parseMessageCacheClear(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType $event")
|
||||
|
||||
val messageId = event[1].asLong()
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
loadMessage(messageId)?.let { message ->
|
||||
listenersMap[LongPollEvent.MESSAGE_EDITED]?.let {
|
||||
loadMessage(messageId = messageId)?.let { message ->
|
||||
listenersMap[LongPollEvent.MESSAGE_CACHE_CLEAR]?.let {
|
||||
it.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.MessageEdited>)
|
||||
.onEvent(LongPollParsedEvent.MessageEdited(message))
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.MessageCacheClear>)
|
||||
.onEvent(LongPollParsedEvent.MessageCacheClear(message))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageReadIncoming(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val peerId = event[1].asInt()
|
||||
val messageId = event[2].asInt()
|
||||
val unreadCount = event[3].asInt()
|
||||
private suspend fun loadMessage(
|
||||
peerId: Long? = null,
|
||||
cmId: Long? = null,
|
||||
messageId: Long? = null
|
||||
): VkMessage? = suspendCoroutine { continuation ->
|
||||
require((peerId != null && cmId != null) || messageId != null)
|
||||
|
||||
listenersMap[LongPollEvent.INCOMING_MESSAGE_READ]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.IncomingMessageRead>)
|
||||
.onEvent(
|
||||
LongPollParsedEvent.IncomingMessageRead(
|
||||
peerId = peerId,
|
||||
messageId = messageId,
|
||||
unreadCount = unreadCount
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageReadOutgoing(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val peerId = event[1].asInt()
|
||||
val messageId = event[2].asInt()
|
||||
val unreadCount = event[3].asInt()
|
||||
|
||||
listenersMap[LongPollEvent.OUTGOING_MESSAGE_READ]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollParsedEvent.OutgoingMessageRead>)
|
||||
.onEvent(
|
||||
LongPollParsedEvent.OutgoingMessageRead(
|
||||
peerId = peerId,
|
||||
messageId = messageId,
|
||||
unreadCount = unreadCount
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChatClearFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
}
|
||||
|
||||
private fun parseChatSetFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
}
|
||||
|
||||
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) {
|
||||
messagesUseCase.getById(
|
||||
messageIds = listOf(messageId),
|
||||
peerCmIds = null,
|
||||
peerId = peerId,
|
||||
messageIds = messageId?.let(::listOf),
|
||||
cmIds = cmId?.let(::listOf),
|
||||
extended = true,
|
||||
fields = VkConstants.ALL_FIELDS
|
||||
).listenValue(this) { state ->
|
||||
@@ -478,9 +666,6 @@ class LongPollUpdatesParser(
|
||||
return@listenValue
|
||||
}
|
||||
|
||||
VkMemoryCache[message.id] = message
|
||||
messagesUseCase.storeMessage(message)
|
||||
|
||||
continuation.resume(message)
|
||||
}
|
||||
)
|
||||
@@ -488,6 +673,35 @@ class LongPollUpdatesParser(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadConversation(
|
||||
peerId: Long,
|
||||
extended: Boolean = false,
|
||||
fields: String? = null
|
||||
): VkConversation? = suspendCoroutine { continuation ->
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
conversationsUseCase.getById(
|
||||
peerIds = listOf(peerId),
|
||||
extended = extended,
|
||||
fields = fields
|
||||
).listenValue(coroutineScope) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
Log.e("LongPollUpdatesParser", "loadConversation: error: $error")
|
||||
continuation.resume(null)
|
||||
},
|
||||
success = { response ->
|
||||
val conversation = response.singleOrNull() ?: run {
|
||||
continuation.resume(null)
|
||||
return@listenValue
|
||||
}
|
||||
|
||||
continuation.resume(conversation)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <T : LongPollParsedEvent> registerListener(
|
||||
eventType: LongPollEvent,
|
||||
@@ -564,6 +778,10 @@ class LongPollUpdatesParser(
|
||||
registerListener(LongPollEvent.CHAT_MINOR_CHANGED, assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onChatArchived(block: (LongPollParsedEvent.ChatArchived) -> Unit) {
|
||||
registerListener(LongPollEvent.CHAT_ARCHIVED, assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onInteractions(block: (LongPollParsedEvent.Interaction) -> Unit) {
|
||||
registerListeners(
|
||||
eventTypes = listOf(
|
||||
@@ -576,10 +794,6 @@ class LongPollUpdatesParser(
|
||||
listener = assembleEventCallback(block)
|
||||
)
|
||||
}
|
||||
|
||||
fun clearListeners() {
|
||||
listenersMap.clear()
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <R : LongPollParsedEvent> assembleEventCallback(
|
||||
|
||||
@@ -5,71 +5,77 @@ import dev.meloda.fast.data.api.messages.MessagesHistoryInfo
|
||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||
import dev.meloda.fast.model.api.domain.VkAttachmentHistoryMessage
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.model.api.responses.MessagesSendResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface MessagesUseCase {
|
||||
interface MessagesUseCase : BaseUseCase {
|
||||
|
||||
suspend fun storeMessage(message: VkMessage)
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
|
||||
fun getMessagesHistory(
|
||||
conversationId: Int,
|
||||
conversationId: Long,
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<MessagesHistoryInfo>>
|
||||
|
||||
fun getById(
|
||||
messageIds: List<Int>,
|
||||
peerCmIds: List<Long>?,
|
||||
peerId: Long?,
|
||||
messageIds: List<Long>?,
|
||||
cmIds: List<Long>?,
|
||||
extended: Boolean?,
|
||||
fields: String?
|
||||
): Flow<State<List<VkMessage>>>
|
||||
|
||||
fun sendMessage(
|
||||
peerId: Int,
|
||||
randomId: Int,
|
||||
peerId: Long,
|
||||
randomId: Long,
|
||||
message: String?,
|
||||
replyTo: Int?,
|
||||
replyTo: Long?,
|
||||
attachments: List<VkAttachment>?
|
||||
): Flow<State<Int>>
|
||||
): Flow<State<MessagesSendResponse>>
|
||||
|
||||
fun markAsRead(
|
||||
peerId: Int,
|
||||
startMessageId: Int
|
||||
peerId: Long,
|
||||
startMessageId: Long
|
||||
): Flow<State<Int>>
|
||||
|
||||
fun getHistoryAttachments(
|
||||
peerId: Int,
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
peerId: Long,
|
||||
count: Int? = null,
|
||||
offset: Int? = null,
|
||||
attachmentTypes: List<String>,
|
||||
conversationMessageId: Int
|
||||
cmId: Long
|
||||
): Flow<State<List<VkAttachmentHistoryMessage>>>
|
||||
|
||||
fun createChat(
|
||||
userIds: List<Int>?,
|
||||
title: String?
|
||||
): Flow<State<Int>>
|
||||
userIds: List<Long>? = null,
|
||||
title: String
|
||||
): Flow<State<Long>>
|
||||
|
||||
fun pin(
|
||||
peerId: Int,
|
||||
messageId: Int?,
|
||||
conversationMessageId: Int?
|
||||
peerId: Long,
|
||||
messageId: Long? = null,
|
||||
cmId: Long? = null
|
||||
): Flow<State<VkMessage>>
|
||||
|
||||
fun unpin(
|
||||
peerId: Int
|
||||
peerId: Long
|
||||
): Flow<State<Int>>
|
||||
|
||||
fun markAsImportant(
|
||||
peerId: Int,
|
||||
messageIds: List<Int>,
|
||||
peerId: Long,
|
||||
messageIds: List<Long>? = null,
|
||||
cmIds: List<Long>? = null,
|
||||
important: Boolean
|
||||
): Flow<State<List<Int>>>
|
||||
): Flow<State<List<Long>>>
|
||||
|
||||
fun delete(
|
||||
peerId: Int,
|
||||
messageIds: List<Int>,
|
||||
peerId: Long,
|
||||
messageIds: List<Long>? = null,
|
||||
cmIds: List<Long>? = null,
|
||||
spam: Boolean = false,
|
||||
deleteForAll: Boolean = false
|
||||
): Flow<State<List<Any>>>
|
||||
|
||||
suspend fun storeMessage(message: VkMessage)
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
}
|
||||
|
||||
@@ -7,163 +7,13 @@ import dev.meloda.fast.data.mapToState
|
||||
import dev.meloda.fast.model.api.domain.VkAttachment
|
||||
import dev.meloda.fast.model.api.domain.VkAttachmentHistoryMessage
|
||||
import dev.meloda.fast.model.api.domain.VkMessage
|
||||
import dev.meloda.fast.model.api.responses.MessagesSendResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class MessagesUseCaseImpl(
|
||||
private val repository: MessagesRepository
|
||||
private val repository: MessagesRepository,
|
||||
) : MessagesUseCase {
|
||||
|
||||
override fun getMessagesHistory(
|
||||
conversationId: Int,
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<MessagesHistoryInfo>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getHistory(
|
||||
conversationId = conversationId,
|
||||
offset = offset,
|
||||
count = count
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun getById(
|
||||
messageIds: List<Int>,
|
||||
extended: Boolean?,
|
||||
fields: String?
|
||||
): Flow<State<List<VkMessage>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getById(
|
||||
messagesIds = messageIds,
|
||||
extended = extended,
|
||||
fields = fields
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun sendMessage(
|
||||
peerId: Int,
|
||||
randomId: Int,
|
||||
message: String?,
|
||||
replyTo: Int?,
|
||||
attachments: List<VkAttachment>?
|
||||
): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.send(
|
||||
peerId = peerId,
|
||||
randomId = randomId,
|
||||
message = message,
|
||||
replyTo = replyTo,
|
||||
attachments = attachments
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun markAsRead(
|
||||
peerId: Int,
|
||||
startMessageId: Int
|
||||
): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.markAsRead(
|
||||
peerId = peerId,
|
||||
startMessageId = startMessageId
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun getHistoryAttachments(
|
||||
peerId: Int,
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
attachmentTypes: List<String>,
|
||||
conversationMessageId: Int
|
||||
): Flow<State<List<VkAttachmentHistoryMessage>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getHistoryAttachments(
|
||||
peerId = peerId,
|
||||
count = count,
|
||||
offset = offset,
|
||||
attachmentTypes = attachmentTypes,
|
||||
conversationMessageId = conversationMessageId
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun createChat(userIds: List<Int>?, title: String?): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
val newState = repository.createChat(userIds, title).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun pin(
|
||||
peerId: Int,
|
||||
messageId: Int?,
|
||||
conversationMessageId: Int?
|
||||
): Flow<State<VkMessage>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.pin(
|
||||
peerId = peerId,
|
||||
messageId = messageId,
|
||||
conversationMessageId = conversationMessageId
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun unpin(peerId: Int): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
val newState = repository.unpin(peerId = peerId).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun markAsImportant(
|
||||
peerId: Int,
|
||||
messageIds: List<Int>,
|
||||
important: Boolean
|
||||
): Flow<State<List<Int>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.markAsImportant(
|
||||
peerId = peerId,
|
||||
messageIds = messageIds,
|
||||
conversationMessageIds = null,
|
||||
important = important
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun delete(
|
||||
peerId: Int,
|
||||
messageIds: List<Int>,
|
||||
spam: Boolean,
|
||||
deleteForAll: Boolean
|
||||
): Flow<State<List<Any>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.delete(
|
||||
peerId = peerId,
|
||||
messageIds = messageIds,
|
||||
conversationMessageIds = null,
|
||||
spam = spam,
|
||||
deleteForAll = deleteForAll
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun storeMessage(message: VkMessage) {
|
||||
repository.storeMessages(listOf(message))
|
||||
}
|
||||
@@ -171,4 +21,129 @@ class MessagesUseCaseImpl(
|
||||
override suspend fun storeMessages(messages: List<VkMessage>) {
|
||||
repository.storeMessages(messages)
|
||||
}
|
||||
|
||||
override fun getMessagesHistory(
|
||||
conversationId: Long,
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<MessagesHistoryInfo>> = flowNewState {
|
||||
repository.getHistory(
|
||||
conversationId = conversationId,
|
||||
offset = offset,
|
||||
count = count
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun getById(
|
||||
peerCmIds: List<Long>?,
|
||||
peerId: Long?,
|
||||
messageIds: List<Long>?,
|
||||
cmIds: List<Long>?,
|
||||
extended: Boolean?,
|
||||
fields: String?
|
||||
): Flow<State<List<VkMessage>>> = flowNewState {
|
||||
repository.getById(
|
||||
peerCmIds = peerCmIds,
|
||||
peerId = peerId,
|
||||
messagesIds = messageIds,
|
||||
cmIds = cmIds,
|
||||
extended = extended,
|
||||
fields = fields
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun sendMessage(
|
||||
peerId: Long,
|
||||
randomId: Long,
|
||||
message: String?,
|
||||
replyTo: Long?,
|
||||
attachments: List<VkAttachment>?
|
||||
): Flow<State<MessagesSendResponse>> = flowNewState {
|
||||
repository.send(
|
||||
peerId = peerId,
|
||||
randomId = randomId,
|
||||
message = message,
|
||||
replyTo = replyTo,
|
||||
attachments = attachments
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun markAsRead(
|
||||
peerId: Long,
|
||||
startMessageId: Long
|
||||
): Flow<State<Int>> = flowNewState {
|
||||
repository.markAsRead(
|
||||
peerId = peerId,
|
||||
startMessageId = startMessageId
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun getHistoryAttachments(
|
||||
peerId: Long,
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
attachmentTypes: List<String>,
|
||||
cmId: Long
|
||||
): Flow<State<List<VkAttachmentHistoryMessage>>> = flowNewState {
|
||||
repository.getHistoryAttachments(
|
||||
peerId = peerId,
|
||||
count = count,
|
||||
offset = offset,
|
||||
attachmentTypes = attachmentTypes,
|
||||
cmId = cmId
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun createChat(
|
||||
userIds: List<Long>?,
|
||||
title: String
|
||||
): Flow<State<Long>> = flowNewState {
|
||||
repository.createChat(userIds, title).mapToState()
|
||||
}
|
||||
|
||||
override fun pin(
|
||||
peerId: Long,
|
||||
messageId: Long?,
|
||||
cmId: Long?
|
||||
): Flow<State<VkMessage>> = flowNewState {
|
||||
repository.pin(
|
||||
peerId = peerId,
|
||||
messageId = messageId,
|
||||
cmId = cmId
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun unpin(peerId: Long): Flow<State<Int>> = flowNewState {
|
||||
repository.unpin(peerId = peerId).mapToState()
|
||||
}
|
||||
|
||||
override fun markAsImportant(
|
||||
peerId: Long,
|
||||
messageIds: List<Long>?,
|
||||
cmIds: List<Long>?,
|
||||
important: Boolean
|
||||
): Flow<State<List<Long>>> = flowNewState {
|
||||
repository.markAsImportant(
|
||||
peerId = peerId,
|
||||
messageIds = messageIds,
|
||||
cmIds = cmIds,
|
||||
important = important
|
||||
).mapToState()
|
||||
}
|
||||
|
||||
override fun delete(
|
||||
peerId: Long,
|
||||
messageIds: List<Long>?,
|
||||
cmIds: List<Long>?,
|
||||
spam: Boolean,
|
||||
deleteForAll: Boolean
|
||||
): Flow<State<List<Any>>> = flowNewState {
|
||||
repository.delete(
|
||||
peerId = peerId,
|
||||
messageIds = messageIds,
|
||||
cmIds = cmIds,
|
||||
spam = spam,
|
||||
deleteForAll = deleteForAll
|
||||
).mapToState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.meloda.fast.domain
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.model.AuthInfo
|
||||
import dev.meloda.fast.model.api.responses.GetSilentTokenResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface OAuthUseCase {
|
||||
@@ -14,4 +15,13 @@ interface OAuthUseCase {
|
||||
captchaSid: String?,
|
||||
captchaKey: String?
|
||||
): Flow<State<AuthInfo>>
|
||||
|
||||
fun getSilentToken(
|
||||
login: String,
|
||||
password: String,
|
||||
forceSms: Boolean,
|
||||
validationCode: String?,
|
||||
captchaSid: String?,
|
||||
captchaKey: String?
|
||||
): Flow<State<GetSilentTokenResponse>>
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ package dev.meloda.fast.domain
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.api.oauth.OAuthRepository
|
||||
import dev.meloda.fast.data.asState
|
||||
import dev.meloda.fast.model.AuthInfo
|
||||
import dev.meloda.fast.network.OAuthErrorDomain
|
||||
import dev.meloda.fast.network.ValidationType
|
||||
import dev.meloda.fast.network.VkOAuthError
|
||||
import dev.meloda.fast.network.VkOAuthErrorType
|
||||
import dev.meloda.fast.model.api.responses.GetSilentTokenResponse
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
@@ -24,109 +22,45 @@ class OAuthUseCaseImpl(
|
||||
): Flow<State<AuthInfo>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val response = oAuthRepository.auth(
|
||||
val newState = oAuthRepository.auth(
|
||||
login = login,
|
||||
password = password,
|
||||
forceSms = forceSms,
|
||||
validationCode = validationCode,
|
||||
captchaSid = captchaSid,
|
||||
captchaKey = captchaKey,
|
||||
forceSms = forceSms
|
||||
)
|
||||
|
||||
kotlin.runCatching {
|
||||
val error = response.error?.let(VkOAuthError::parse)
|
||||
val errorType = response.errorType?.let(VkOAuthErrorType::parse)
|
||||
|
||||
val newState = when (error) {
|
||||
null -> {
|
||||
State.Success(
|
||||
AuthInfo(
|
||||
userId = response.userId,
|
||||
accessToken = response.accessToken,
|
||||
validationHash = response.validationHash
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
VkOAuthError.FLOOD_CONTROL -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.TooManyTriesError)
|
||||
}
|
||||
|
||||
VkOAuthError.NEED_VALIDATION -> {
|
||||
if (response.banInfo != null) {
|
||||
val info = requireNotNull(response.banInfo)
|
||||
|
||||
State.Error.OAuthError(
|
||||
OAuthErrorDomain.UserBannedError(
|
||||
memberName = info.memberName,
|
||||
message = info.message,
|
||||
accessToken = info.accessToken,
|
||||
restoreUrl = info.restoreUrl
|
||||
)
|
||||
)
|
||||
} else {
|
||||
State.Error.OAuthError(
|
||||
OAuthErrorDomain.ValidationRequiredError(
|
||||
description = response.errorDescription.orEmpty(),
|
||||
validationType = response.validationType.orEmpty()
|
||||
.let(ValidationType::parse),
|
||||
validationSid = response.validationSid.orEmpty(),
|
||||
phoneMask = response.phoneMask.orEmpty(),
|
||||
redirectUri = response.redirectUri.orEmpty(),
|
||||
validationResend = response.validationResend,
|
||||
restoreIfCannotGetCode = response.restoreIfCannotGetCode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
VkOAuthError.NEED_CAPTCHA -> {
|
||||
State.Error.OAuthError(
|
||||
OAuthErrorDomain.CaptchaRequiredError(
|
||||
captchaSid = response.captchaSid.orEmpty(),
|
||||
captchaImageUrl = response.captchaImage.orEmpty()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
VkOAuthError.INVALID_CLIENT -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.InvalidCredentialsError)
|
||||
}
|
||||
|
||||
VkOAuthError.INVALID_REQUEST -> {
|
||||
when (errorType) {
|
||||
null -> State.Error.OAuthError(OAuthErrorDomain.UnknownError)
|
||||
|
||||
VkOAuthErrorType.WRONG_OTP -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.WrongValidationCode)
|
||||
}
|
||||
|
||||
VkOAuthErrorType.WRONG_OTP_FORMAT -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.WrongValidationCodeFormat)
|
||||
}
|
||||
|
||||
VkOAuthErrorType.PASSWORD_BRUTEFORCE_ATTEMPT -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.TooManyTriesError)
|
||||
}
|
||||
|
||||
VkOAuthErrorType.USERNAME_OR_PASSWORD_IS_INCORRECT -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.InvalidCredentialsError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VkOAuthError.UNKNOWN -> {
|
||||
State.Error.OAuthError(OAuthErrorDomain.UnknownError)
|
||||
}
|
||||
}
|
||||
|
||||
emit(newState)
|
||||
}.fold(
|
||||
onSuccess = {
|
||||
},
|
||||
onFailure = {
|
||||
emit(State.Error.TestError(it.stackTraceToString()))
|
||||
captchaKey = captchaKey
|
||||
).asState(
|
||||
successMapper = {
|
||||
AuthInfo(
|
||||
userId = it.userId!!,
|
||||
accessToken = it.accessToken!!,
|
||||
validationHash = it.validationHash!!
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun getSilentToken(
|
||||
login: String,
|
||||
password: String,
|
||||
forceSms: Boolean,
|
||||
validationCode: String?,
|
||||
captchaSid: String?,
|
||||
captchaKey: String?
|
||||
): Flow<State<GetSilentTokenResponse>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = oAuthRepository.getSilentToken(
|
||||
login = login,
|
||||
password = password,
|
||||
forceSms = forceSms,
|
||||
validationCode = validationCode,
|
||||
captchaSid = captchaSid,
|
||||
captchaKey = captchaKey
|
||||
).asState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user