domain module
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
alias(libs.plugins.fast.android.library)
|
||||
// alias(libs.plugins.fast.koin)
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -13,9 +14,8 @@ dependencies {
|
||||
api(projects.core.network)
|
||||
api(projects.core.database)
|
||||
|
||||
implementation(libs.koin.android)
|
||||
|
||||
// TODO: 05/05/2024, Danil Nikolaev: research, maybe remove
|
||||
// TODO: 11/08/2024, Danil Nikolaev: remove?
|
||||
implementation(libs.retrofit)
|
||||
implementation(libs.eithernet)
|
||||
implementation(libs.koin.android)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.meloda.fast.data
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.net.URLEncoder
|
||||
|
||||
class AccessTokenInterceptor : Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val builder = chain.request().url.newBuilder()
|
||||
|
||||
val uri = builder.build().toUri().toString().toUri()
|
||||
|
||||
if (uri.getQueryParameter("access_token") == null) {
|
||||
builder.addQueryParameter(
|
||||
"access_token",
|
||||
URLEncoder.encode(UserConfig.accessToken, "utf-8")
|
||||
)
|
||||
}
|
||||
|
||||
return chain.proceed(chain.request().newBuilder().apply { url(builder.build()) }.build())
|
||||
}
|
||||
}
|
||||
@@ -1,360 +0,0 @@
|
||||
package dev.meloda.fast.data
|
||||
|
||||
import android.util.Log
|
||||
import dev.meloda.fast.common.UserConfig
|
||||
import dev.meloda.fast.common.VkConstants
|
||||
import dev.meloda.fast.common.extensions.asInt
|
||||
import dev.meloda.fast.common.extensions.listenValue
|
||||
import dev.meloda.fast.common.extensions.toList
|
||||
import dev.meloda.fast.data.api.messages.MessagesUseCase
|
||||
import dev.meloda.fast.model.ApiEvent
|
||||
import dev.meloda.fast.model.InteractionType
|
||||
import dev.meloda.fast.model.LongPollEvent
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
class LongPollUpdatesParser(
|
||||
private val messagesUseCase: MessagesUseCase
|
||||
) {
|
||||
private val job = SupervisorJob()
|
||||
|
||||
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
|
||||
Log.d("LongPollUpdatesParser", "error: $throwable")
|
||||
throwable.printStackTrace()
|
||||
}
|
||||
|
||||
private val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Default + job + exceptionHandler
|
||||
|
||||
private val coroutineScope = CoroutineScope(coroutineContext)
|
||||
|
||||
private val listenersMap: MutableMap<ApiEvent, MutableCollection<VkEventCallback<*>>> =
|
||||
mutableMapOf()
|
||||
|
||||
fun parseNextUpdate(event: List<Any>) {
|
||||
val eventId = event.first().asInt()
|
||||
|
||||
val eventType: ApiEvent = try {
|
||||
ApiEvent.parse(eventId)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Log.d("LongPollUpdatesParser", "parseNextUpdate: unknownEvent: $event")
|
||||
return
|
||||
}
|
||||
|
||||
when (eventType) {
|
||||
ApiEvent.MESSAGE_SET_FLAGS -> parseMessageSetFlags(eventType, event)
|
||||
ApiEvent.MESSAGE_CLEAR_FLAGS -> parseMessageClearFlags(eventType, event)
|
||||
ApiEvent.MESSAGE_NEW -> parseMessageNew(eventType, event)
|
||||
ApiEvent.MESSAGE_EDIT -> parseMessageEdit(eventType, event)
|
||||
ApiEvent.MESSAGE_READ_INCOMING -> parseMessageReadIncoming(eventType, event)
|
||||
ApiEvent.MESSAGE_READ_OUTGOING -> parseMessageReadOutgoing(eventType, event)
|
||||
ApiEvent.MESSAGES_DELETED -> parseMessagesDeleted(eventType, event)
|
||||
ApiEvent.PIN_UNPIN_CONVERSATION -> parseConversationPinStateChanged(eventType, event)
|
||||
|
||||
ApiEvent.TYPING,
|
||||
ApiEvent.AUDIO_MESSAGE_RECORDING,
|
||||
ApiEvent.PHOTO_UPLOADING,
|
||||
ApiEvent.VIDEO_UPLOADING,
|
||||
ApiEvent.FILE_UPLOADING -> parseInteraction(eventType, event)
|
||||
|
||||
ApiEvent.UNREAD_COUNT_UPDATE -> onNewEvent(eventType, event)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onNewEvent(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "newEvent: $eventType: $event")
|
||||
}
|
||||
|
||||
private fun parseInteraction(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val interactionType = when (eventType) {
|
||||
ApiEvent.TYPING -> InteractionType.Typing
|
||||
ApiEvent.AUDIO_MESSAGE_RECORDING -> InteractionType.VoiceMessage
|
||||
ApiEvent.PHOTO_UPLOADING -> InteractionType.Photo
|
||||
ApiEvent.VIDEO_UPLOADING -> InteractionType.Video
|
||||
ApiEvent.FILE_UPLOADING -> InteractionType.File
|
||||
else -> return
|
||||
}
|
||||
|
||||
val peerId = event[1].asInt()
|
||||
val userIds = event[2].toList(Any::asInt).filter { it != UserConfig.userId }
|
||||
val totalCount = event[3].asInt()
|
||||
val timestamp = event[4].asInt()
|
||||
|
||||
// if userIds contains only account's id, then we don't need to show our status
|
||||
if (userIds.isEmpty()) return
|
||||
|
||||
coroutineScope.launch {
|
||||
listenersMap[eventType]?.let { listeners ->
|
||||
listeners.forEach { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollEvent.Interaction>)
|
||||
.onEvent(
|
||||
LongPollEvent.Interaction(
|
||||
interactionType = interactionType,
|
||||
peerId = peerId,
|
||||
userIds = userIds,
|
||||
totalCount = totalCount,
|
||||
timestamp = timestamp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseConversationPinStateChanged(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
|
||||
val peerId = event[1].asInt()
|
||||
val majorId = event[2].asInt()
|
||||
|
||||
coroutineScope.launch {
|
||||
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>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
}
|
||||
|
||||
private fun parseMessageClearFlags(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
}
|
||||
|
||||
private fun parseMessageNew(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val messageId = event[1].asInt()
|
||||
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
val newMessageEvent: LongPollEvent.VkMessageNewEvent? =
|
||||
loadNormalMessage(
|
||||
eventType,
|
||||
messageId
|
||||
)
|
||||
|
||||
newMessageEvent?.let { event ->
|
||||
listenersMap[ApiEvent.MESSAGE_NEW]?.let {
|
||||
it.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageNewEvent>)
|
||||
.onEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessageEdit(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
val messageId = event[1].asInt()
|
||||
|
||||
coroutineScope.launch {
|
||||
val editedMessageEvent: LongPollEvent.VkMessageEditEvent? =
|
||||
loadNormalMessage(
|
||||
eventType,
|
||||
messageId
|
||||
)
|
||||
|
||||
editedMessageEvent?.let { event ->
|
||||
listenersMap[ApiEvent.MESSAGE_EDIT]?.let {
|
||||
it.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageEditEvent>)
|
||||
.onEvent(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
coroutineScope.launch {
|
||||
listenersMap[ApiEvent.MESSAGE_READ_INCOMING]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageReadIncomingEvent>)
|
||||
.onEvent(
|
||||
LongPollEvent.VkMessageReadIncomingEvent(
|
||||
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()
|
||||
|
||||
coroutineScope.launch {
|
||||
listenersMap[ApiEvent.MESSAGE_READ_OUTGOING]?.let { listeners ->
|
||||
listeners.map { vkEventCallback ->
|
||||
(vkEventCallback as VkEventCallback<LongPollEvent.VkMessageReadOutgoingEvent>)
|
||||
.onEvent(
|
||||
LongPollEvent.VkMessageReadOutgoingEvent(
|
||||
peerId = peerId,
|
||||
messageId = messageId,
|
||||
unreadCount = unreadCount
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseMessagesDeleted(eventType: ApiEvent, event: List<Any>) {
|
||||
Log.d("LongPollUpdatesParser", "$eventType: $event")
|
||||
}
|
||||
|
||||
private suspend inline fun <reified T : LongPollEvent> loadNormalMessage(
|
||||
eventType: ApiEvent,
|
||||
messageId: Int
|
||||
): T? = suspendCoroutine { continuation ->
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
messagesUseCase.getById(
|
||||
messageIds = listOf(messageId),
|
||||
extended = true,
|
||||
fields = VkConstants.ALL_FIELDS
|
||||
).listenValue(this) { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
Log.e("LongPollUpdatesParser", "loadNormalMessage: error: $error")
|
||||
},
|
||||
success = { messages ->
|
||||
val message = messages.singleOrNull() ?: run {
|
||||
continuation.resume(null)
|
||||
return@listenValue
|
||||
}
|
||||
|
||||
VkMemoryCache[message.id] = message
|
||||
messagesUseCase.storeMessage(message)
|
||||
|
||||
val resumeValue: LongPollEvent? = when (eventType) {
|
||||
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 : Any> registerListener(
|
||||
eventType: ApiEvent,
|
||||
listener: VkEventCallback<T>
|
||||
) {
|
||||
listenersMap.let { map ->
|
||||
map[eventType] = (map[eventType] ?: mutableListOf()).also { it.add(listener) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : Any> registerListeners(
|
||||
eventTypes: List<ApiEvent>,
|
||||
listener: VkEventCallback<T>
|
||||
) {
|
||||
eventTypes.forEach { eventType -> registerListener(eventType, listener) }
|
||||
}
|
||||
|
||||
fun onConversationPinStateChanged(listener: VkEventCallback<LongPollEvent.VkConversationPinStateChangedEvent>) {
|
||||
registerListener(ApiEvent.PIN_UNPIN_CONVERSATION, listener)
|
||||
}
|
||||
|
||||
fun onConversationPinStateChanged(block: (LongPollEvent.VkConversationPinStateChangedEvent) -> Unit) {
|
||||
onConversationPinStateChanged(assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onMessageIncomingRead(listener: VkEventCallback<LongPollEvent.VkMessageReadIncomingEvent>) {
|
||||
registerListener(ApiEvent.MESSAGE_READ_INCOMING, listener)
|
||||
}
|
||||
|
||||
fun onMessageIncomingRead(block: (LongPollEvent.VkMessageReadIncomingEvent) -> Unit) {
|
||||
onMessageIncomingRead(assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onMessageOutgoingRead(listener: VkEventCallback<LongPollEvent.VkMessageReadOutgoingEvent>) {
|
||||
registerListener(ApiEvent.MESSAGE_READ_OUTGOING, listener)
|
||||
}
|
||||
|
||||
fun onMessageOutgoingRead(block: (LongPollEvent.VkMessageReadOutgoingEvent) -> Unit) {
|
||||
onMessageOutgoingRead(assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onNewMessage(listener: VkEventCallback<LongPollEvent.VkMessageNewEvent>) {
|
||||
registerListener(ApiEvent.MESSAGE_NEW, listener)
|
||||
}
|
||||
|
||||
fun onNewMessage(block: (LongPollEvent.VkMessageNewEvent) -> Unit) {
|
||||
onNewMessage(assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onMessageEdited(listener: VkEventCallback<LongPollEvent.VkMessageEditEvent>) {
|
||||
registerListener(ApiEvent.MESSAGE_EDIT, listener)
|
||||
}
|
||||
|
||||
fun onMessageEdited(block: (LongPollEvent.VkMessageEditEvent) -> Unit) {
|
||||
onMessageEdited(assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun onInteractions(listener: VkEventCallback<LongPollEvent.Interaction>) {
|
||||
registerListeners(
|
||||
eventTypes = listOf(
|
||||
ApiEvent.TYPING,
|
||||
ApiEvent.AUDIO_MESSAGE_RECORDING,
|
||||
ApiEvent.PHOTO_UPLOADING,
|
||||
ApiEvent.VIDEO_UPLOADING,
|
||||
ApiEvent.FILE_UPLOADING
|
||||
),
|
||||
listener = listener
|
||||
)
|
||||
}
|
||||
|
||||
fun onInteractions(block: (LongPollEvent.Interaction) -> Unit) {
|
||||
onInteractions(assembleEventCallback(block))
|
||||
}
|
||||
|
||||
fun clearListeners() {
|
||||
listenersMap.clear()
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <R : Any> assembleEventCallback(
|
||||
crossinline block: (R) -> Unit,
|
||||
): VkEventCallback<R> {
|
||||
return VkEventCallback { event -> block.invoke(event) }
|
||||
}
|
||||
|
||||
fun interface VkEventCallback<in T : Any> {
|
||||
fun onEvent(event: T)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package dev.meloda.fast.data
|
||||
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface LongPollUseCase {
|
||||
|
||||
fun getLongPollServer(
|
||||
needPts: Boolean,
|
||||
version: Int
|
||||
): Flow<State<VkLongPollData>>
|
||||
|
||||
fun getLongPollUpdates(
|
||||
serverUrl: String,
|
||||
act: String = "a_check",
|
||||
key: String,
|
||||
ts: Int,
|
||||
wait: Int,
|
||||
mode: Int,
|
||||
version: Int
|
||||
): Flow<State<LongPollUpdates>>
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package dev.meloda.fast.data
|
||||
|
||||
import dev.meloda.fast.data.api.longpoll.LongPollRepository
|
||||
import dev.meloda.fast.model.api.data.LongPollUpdates
|
||||
import dev.meloda.fast.model.api.data.VkLongPollData
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class LongPollUseCaseImpl(
|
||||
private val repository: LongPollRepository
|
||||
) : LongPollUseCase {
|
||||
|
||||
override fun getLongPollServer(
|
||||
needPts: Boolean,
|
||||
version: Int
|
||||
): Flow<State<VkLongPollData>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getLongPollServer(
|
||||
needPts = needPts,
|
||||
version = version
|
||||
).mapToState()
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun getLongPollUpdates(
|
||||
serverUrl: String,
|
||||
act: String,
|
||||
key: String,
|
||||
ts: Int,
|
||||
wait: Int,
|
||||
mode: Int,
|
||||
version: Int
|
||||
): Flow<State<LongPollUpdates>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.getLongPollUpdates(
|
||||
serverUrl,
|
||||
act = act,
|
||||
key = key,
|
||||
ts = ts,
|
||||
wait = wait,
|
||||
mode = mode,
|
||||
version = version
|
||||
).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.meloda.fast.data
|
||||
|
||||
import dev.meloda.fast.datastore.AppSettings
|
||||
|
||||
object UserConfig {
|
||||
|
||||
private const val ARG_CURRENT_USER_ID = "current_user_id"
|
||||
|
||||
var currentUserId: Int = -1
|
||||
get() = AppSettings.getInt(ARG_CURRENT_USER_ID, -1)
|
||||
set(value) {
|
||||
field = value
|
||||
AppSettings.edit { putInt(ARG_CURRENT_USER_ID, value) }
|
||||
}
|
||||
|
||||
var userId: Int = -1
|
||||
var accessToken: String = ""
|
||||
var fastToken: String? = ""
|
||||
var trustedHash: String? = null
|
||||
|
||||
fun clear() {
|
||||
currentUserId = -1
|
||||
accessToken = ""
|
||||
fastToken = ""
|
||||
userId = -1
|
||||
}
|
||||
|
||||
fun isLoggedIn(): Boolean {
|
||||
return currentUserId > 0 && userId > 0 && accessToken.isNotBlank()
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package dev.meloda.fast.data.api.account
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AccountUseCase {
|
||||
|
||||
suspend fun setOnline(
|
||||
voip: Boolean,
|
||||
accessToken: String
|
||||
): Flow<State<Int>>
|
||||
|
||||
suspend fun setOffline(
|
||||
accessToken: String
|
||||
): Flow<State<Int>>
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package dev.meloda.fast.data.api.account
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.mapToState
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class AccountUseCaseImpl(
|
||||
private val repository: AccountRepository
|
||||
) : AccountUseCase {
|
||||
|
||||
override suspend fun setOnline(
|
||||
voip: Boolean,
|
||||
accessToken: String
|
||||
): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.setOnline(voip = voip).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun setOffline(
|
||||
accessToken: String
|
||||
): Flow<State<Int>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.setOffline().mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package dev.meloda.fast.data.api.conversations
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
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>>
|
||||
|
||||
suspend fun storeConversations(conversations: List<VkConversation>)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package dev.meloda.fast.data.api.friends
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.model.FriendsInfo
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface FriendsUseCase {
|
||||
|
||||
fun getAllFriends(
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<FriendsInfo>>
|
||||
|
||||
fun getFriends(
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<List<VkUser>>>
|
||||
|
||||
fun getOnlineFriends(
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<List<Int>>>
|
||||
|
||||
suspend fun storeUsers(users: List<VkUser>)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package dev.meloda.fast.data.api.messages
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
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 kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface MessagesUseCase {
|
||||
|
||||
fun getMessagesHistory(
|
||||
conversationId: Int,
|
||||
count: Int?,
|
||||
offset: Int?
|
||||
): Flow<State<MessagesHistoryInfo>>
|
||||
|
||||
fun getById(
|
||||
messageIds: List<Int>,
|
||||
extended: Boolean?,
|
||||
fields: String?
|
||||
): Flow<State<List<VkMessage>>>
|
||||
|
||||
fun sendMessage(
|
||||
peerId: Int,
|
||||
randomId: Int,
|
||||
message: String?,
|
||||
replyTo: Int?,
|
||||
attachments: List<VkAttachment>?
|
||||
): Flow<State<Int>>
|
||||
|
||||
fun markAsRead(
|
||||
peerId: Int,
|
||||
startMessageId: Int
|
||||
): Flow<State<Int>>
|
||||
|
||||
fun getHistoryAttachments(
|
||||
peerId: Int,
|
||||
count: Int?,
|
||||
offset: Int?,
|
||||
attachmentTypes: List<String>,
|
||||
conversationMessageId: Int
|
||||
): Flow<State<List<VkAttachmentHistoryMessage>>>
|
||||
|
||||
suspend fun storeMessage(message: VkMessage)
|
||||
suspend fun storeMessages(messages: List<VkMessage>)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package dev.meloda.fast.data.api.users
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface UsersUseCase {
|
||||
|
||||
fun get(
|
||||
userIds: List<Int>?,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): Flow<State<List<VkUser>>>
|
||||
|
||||
fun getLocalUser(userId: Int): Flow<State<VkUser?>>
|
||||
|
||||
suspend fun storeUser(user: VkUser)
|
||||
suspend fun storeUsers(users: List<VkUser>)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package dev.meloda.fast.data.api.users
|
||||
|
||||
import dev.meloda.fast.data.State
|
||||
import dev.meloda.fast.data.mapToState
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class UsersUseCaseImpl(
|
||||
private val repository: UsersRepository,
|
||||
) : UsersUseCase {
|
||||
|
||||
override fun get(
|
||||
userIds: List<Int>?,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): Flow<State<List<VkUser>>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.get(userIds, fields, nomCase).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override fun getLocalUser(userId: Int): Flow<State<VkUser?>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = kotlin.runCatching {
|
||||
repository.getLocalUsers(listOf(userId)).singleOrNull()
|
||||
}.fold(
|
||||
onSuccess = { user -> State.Success(user) },
|
||||
onFailure = { State.Error.InternalError }
|
||||
)
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun storeUser(user: VkUser) = repository.storeUsers(listOf(user))
|
||||
override suspend fun storeUsers(users: List<VkUser>) = repository.storeUsers(users)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package dev.meloda.fast.data.db
|
||||
|
||||
import dev.meloda.fast.common.UserConfig
|
||||
import dev.meloda.fast.model.database.AccountEntity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GetCurrentAccountUseCase(private val accountsRepository: AccountsRepository) {
|
||||
|
||||
suspend operator fun invoke(): AccountEntity? = withContext(Dispatchers.IO) {
|
||||
accountsRepository.getAccountById(UserConfig.currentUserId)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package dev.meloda.fast.data.di
|
||||
|
||||
import dev.meloda.fast.common.di.commonModule
|
||||
import dev.meloda.fast.data.AccessTokenInterceptor
|
||||
import dev.meloda.fast.data.api.account.AccountRepository
|
||||
import dev.meloda.fast.data.api.account.AccountRepositoryImpl
|
||||
import dev.meloda.fast.data.api.account.AccountUseCase
|
||||
import dev.meloda.fast.data.api.account.AccountUseCaseImpl
|
||||
import dev.meloda.fast.data.api.audios.AudiosRepository
|
||||
import dev.meloda.fast.data.api.auth.AuthRepository
|
||||
import dev.meloda.fast.data.api.auth.AuthRepositoryImpl
|
||||
@@ -22,29 +20,26 @@ import dev.meloda.fast.data.api.oauth.OAuthRepositoryImpl
|
||||
import dev.meloda.fast.data.api.photos.PhotosRepository
|
||||
import dev.meloda.fast.data.api.users.UsersRepository
|
||||
import dev.meloda.fast.data.api.users.UsersRepositoryImpl
|
||||
import dev.meloda.fast.data.api.users.UsersUseCase
|
||||
import dev.meloda.fast.data.api.users.UsersUseCaseImpl
|
||||
import dev.meloda.fast.data.api.videos.VideosRepository
|
||||
import dev.meloda.fast.data.db.AccountsRepository
|
||||
import dev.meloda.fast.data.db.AccountsRepositoryImpl
|
||||
import dev.meloda.fast.data.db.GetCurrentAccountUseCase
|
||||
import dev.meloda.fast.database.di.databaseModule
|
||||
import dev.meloda.fast.datastore.di.dataStoreModule
|
||||
import dev.meloda.fast.network.di.networkModule
|
||||
import okhttp3.Interceptor
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
val dataModule = module {
|
||||
includes(
|
||||
commonModule,
|
||||
databaseModule,
|
||||
dataStoreModule,
|
||||
networkModule,
|
||||
)
|
||||
|
||||
singleOf(::AccountRepositoryImpl) bind AccountRepository::class
|
||||
singleOf(::AccountUseCaseImpl) bind AccountUseCase::class
|
||||
|
||||
singleOf(::AudiosRepository)
|
||||
|
||||
@@ -63,12 +58,15 @@ val dataModule = module {
|
||||
singleOf(::PhotosRepository)
|
||||
|
||||
singleOf(::UsersRepositoryImpl) bind UsersRepository::class
|
||||
singleOf(::UsersUseCaseImpl) bind UsersUseCase::class
|
||||
|
||||
singleOf(::VideosRepository)
|
||||
|
||||
singleOf(::AccountsRepositoryImpl) bind AccountsRepository::class
|
||||
singleOf(::GetCurrentAccountUseCase)
|
||||
|
||||
singleOf(::FriendsRepositoryImpl) bind FriendsRepository::class
|
||||
|
||||
// TODO: 11/08/2024, Danil Nikolaev: find a better solution
|
||||
single<Interceptor>(named("token_interceptor")) {
|
||||
AccessTokenInterceptor()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user