From 58e2906c0fad3c9ce1337785c56afc4c6f91ce3b Mon Sep 17 00:00:00 2001 From: Danil Nikolaev Date: Wed, 14 Aug 2024 21:03:35 +0300 Subject: [PATCH] separation of users use cases --- app/build.gradle.kts | 4 +- .../main/kotlin/dev/meloda/fast/data/State.kt | 11 ++++- .../fast/domain/GetLocalUserByIdUseCase.kt | 23 +++++++++++ .../fast/domain/GetLocalUsersByIdsUseCase.kt | 23 +++++++++++ .../meloda/fast/domain/LoadUserByIdUseCase.kt | 28 +++++++++++++ .../fast/domain/LoadUsersByIdsUseCase.kt | 28 +++++++++++++ .../meloda/fast/domain/StoreUsersUseCase.kt | 28 +++++++++++++ .../dev/meloda/fast/domain/UsersUseCase.kt | 19 --------- .../meloda/fast/domain/UsersUseCaseImpl.kt | 40 ------------------- .../dev/meloda/fast/domain/di/DomainModule.kt | 14 +++++-- .../meloda/fast/auth/login/LoginViewModel.kt | 14 +++---- .../meloda/fast/profile/ProfileViewModel.kt | 14 ++++--- gradle/libs.versions.toml | 4 +- 13 files changed, 170 insertions(+), 80 deletions(-) create mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUserByIdUseCase.kt create mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUsersByIdsUseCase.kt create mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUserByIdUseCase.kt create mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUsersByIdsUseCase.kt create mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/StoreUsersUseCase.kt delete mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCase.kt delete mode 100644 core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCaseImpl.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 649a27c3..56120ebe 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -12,8 +12,8 @@ android { defaultConfig { applicationId = "dev.meloda.fast" - versionCode = 4 - versionName = "0.1.1" + versionCode = libs.versions.versionCode.get().toInt() + versionName = libs.versions.versionName.get() } signingConfigs { diff --git a/core/data/src/main/kotlin/dev/meloda/fast/data/State.kt b/core/data/src/main/kotlin/dev/meloda/fast/data/State.kt index dc8b29d6..b87a0619 100644 --- a/core/data/src/main/kotlin/dev/meloda/fast/data/State.kt +++ b/core/data/src/main/kotlin/dev/meloda/fast/data/State.kt @@ -1,9 +1,9 @@ package dev.meloda.fast.data +import com.slack.eithernet.ApiResult import dev.meloda.fast.network.OAuthErrorDomain import dev.meloda.fast.network.RestApiErrorDomain import dev.meloda.fast.network.VkErrorCode -import com.slack.eithernet.ApiResult sealed class State { @@ -72,3 +72,12 @@ fun ApiResult.mapToState() = when (this) { is ApiResult.Failure.HttpFailure -> this.error.toStateApiError() is ApiResult.Failure.ApiFailure -> this.error.toStateApiError() } + +fun ApiResult.mapToState(successMapper: (T) -> N) = when (this) { + is ApiResult.Success -> State.Success(successMapper(this.value)) + + is ApiResult.Failure.NetworkFailure -> State.Error.ConnectionError + is ApiResult.Failure.UnknownFailure -> State.UNKNOWN_ERROR + is ApiResult.Failure.HttpFailure -> this.error.toStateApiError() + is ApiResult.Failure.ApiFailure -> this.error.toStateApiError() +} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUserByIdUseCase.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUserByIdUseCase.kt new file mode 100644 index 00000000..bf61c2e7 --- /dev/null +++ b/core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUserByIdUseCase.kt @@ -0,0 +1,23 @@ +package dev.meloda.fast.domain + +import dev.meloda.fast.data.State +import dev.meloda.fast.data.api.users.UsersRepository +import dev.meloda.fast.model.api.domain.VkUser +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +class GetLocalUserByIdUseCase(private val repository: UsersRepository) { + + operator fun invoke(userId: Int): Flow> = flow { + emit(State.Loading) + + val newState = kotlin.runCatching { + repository.getLocalUsers(userIds = listOf(userId)).singleOrNull() + }.fold( + onSuccess = { user -> State.Success(user) }, + onFailure = { State.Error.InternalError } + ) + + emit(newState) + } +} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUsersByIdsUseCase.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUsersByIdsUseCase.kt new file mode 100644 index 00000000..e371323a --- /dev/null +++ b/core/domain/src/main/kotlin/dev/meloda/fast/domain/GetLocalUsersByIdsUseCase.kt @@ -0,0 +1,23 @@ +package dev.meloda.fast.domain + +import dev.meloda.fast.data.State +import dev.meloda.fast.data.api.users.UsersRepository +import dev.meloda.fast.model.api.domain.VkUser +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +class GetLocalUsersByIdsUseCase(private val repository: UsersRepository) { + + operator fun invoke(userIds: List): Flow>> = flow { + emit(State.Loading) + + val newState = kotlin.runCatching { + repository.getLocalUsers(userIds = userIds) + }.fold( + onSuccess = { user -> State.Success(user) }, + onFailure = { State.Error.InternalError } + ) + + emit(newState) + } +} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUserByIdUseCase.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUserByIdUseCase.kt new file mode 100644 index 00000000..a8b93a8a --- /dev/null +++ b/core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUserByIdUseCase.kt @@ -0,0 +1,28 @@ +package dev.meloda.fast.domain + +import dev.meloda.fast.common.VkConstants +import dev.meloda.fast.data.State +import dev.meloda.fast.data.api.users.UsersRepository +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 LoadUserByIdUseCase(private val repository: UsersRepository) { + + operator fun invoke( + userId: Int?, + fields: String = VkConstants.USER_FIELDS, + nomCase: String? = null + ): Flow> = flow { + emit(State.Loading) + + val newState = repository.get( + userIds = userId?.let(::listOf), + fields = fields, + nomCase = nomCase + ).mapToState(List::singleOrNull) + + emit(newState) + } +} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUsersByIdsUseCase.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUsersByIdsUseCase.kt new file mode 100644 index 00000000..0f845ba6 --- /dev/null +++ b/core/domain/src/main/kotlin/dev/meloda/fast/domain/LoadUsersByIdsUseCase.kt @@ -0,0 +1,28 @@ +package dev.meloda.fast.domain + +import dev.meloda.fast.common.VkConstants +import dev.meloda.fast.data.State +import dev.meloda.fast.data.api.users.UsersRepository +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 LoadUsersByIdsUseCase(private val repository: UsersRepository) { + + operator fun invoke( + userIds: List?, + fields: String = VkConstants.USER_FIELDS, + nomCase: String? = null + ): Flow>> = flow { + emit(State.Loading) + + val newState = repository.get( + userIds = userIds, + fields = fields, + nomCase = nomCase + ).mapToState() + + emit(newState) + } +} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/StoreUsersUseCase.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/StoreUsersUseCase.kt new file mode 100644 index 00000000..e55186ea --- /dev/null +++ b/core/domain/src/main/kotlin/dev/meloda/fast/domain/StoreUsersUseCase.kt @@ -0,0 +1,28 @@ +package dev.meloda.fast.domain + +import dev.meloda.fast.data.State +import dev.meloda.fast.data.api.users.UsersRepository +import dev.meloda.fast.model.api.domain.VkUser +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +class StoreUsersUseCase(private val repository: UsersRepository) { + + operator fun invoke(users: List): Flow> = flow { + emit(State.Loading) + + val newState = kotlin.runCatching { + repository.storeUsers(users) + }.fold( + onSuccess = { + State.Success(Unit) + }, + onFailure = { error -> + error.printStackTrace() + State.Error.InternalError + } + ) + + emit(newState) + } +} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCase.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCase.kt deleted file mode 100644 index 297e2dda..00000000 --- a/core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCase.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.meloda.fast.domain - -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?, - fields: String?, - nomCase: String? - ): Flow>> - - fun getLocalUser(userId: Int): Flow> - - suspend fun storeUser(user: VkUser) - suspend fun storeUsers(users: List) -} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCaseImpl.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCaseImpl.kt deleted file mode 100644 index b7d50817..00000000 --- a/core/domain/src/main/kotlin/dev/meloda/fast/domain/UsersUseCaseImpl.kt +++ /dev/null @@ -1,40 +0,0 @@ -package dev.meloda.fast.domain - -import dev.meloda.fast.data.State -import dev.meloda.fast.data.api.users.UsersRepository -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?, - fields: String?, - nomCase: String? - ): Flow>> = flow { - emit(State.Loading) - - val newState = repository.get(userIds, fields, nomCase).mapToState() - emit(newState) - } - - override fun getLocalUser(userId: Int): Flow> = 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) = repository.storeUsers(users) -} diff --git a/core/domain/src/main/kotlin/dev/meloda/fast/domain/di/DomainModule.kt b/core/domain/src/main/kotlin/dev/meloda/fast/domain/di/DomainModule.kt index 96e41ca8..9fccd341 100644 --- a/core/domain/src/main/kotlin/dev/meloda/fast/domain/di/DomainModule.kt +++ b/core/domain/src/main/kotlin/dev/meloda/fast/domain/di/DomainModule.kt @@ -4,8 +4,11 @@ import dev.meloda.fast.data.di.dataModule import dev.meloda.fast.domain.AccountUseCase import dev.meloda.fast.domain.AccountUseCaseImpl import dev.meloda.fast.domain.GetCurrentAccountUseCase -import dev.meloda.fast.domain.UsersUseCase -import dev.meloda.fast.domain.UsersUseCaseImpl +import dev.meloda.fast.domain.GetLocalUserByIdUseCase +import dev.meloda.fast.domain.GetLocalUsersByIdsUseCase +import dev.meloda.fast.domain.LoadUserByIdUseCase +import dev.meloda.fast.domain.LoadUsersByIdsUseCase +import dev.meloda.fast.domain.StoreUsersUseCase import org.koin.core.module.dsl.singleOf import org.koin.dsl.bind import org.koin.dsl.module @@ -13,7 +16,12 @@ import org.koin.dsl.module val domainModule = module { includes(dataModule) - singleOf(::UsersUseCaseImpl) bind UsersUseCase::class + singleOf(::GetLocalUserByIdUseCase) + singleOf(::GetLocalUsersByIdsUseCase) + singleOf(::LoadUserByIdUseCase) + singleOf(::LoadUsersByIdsUseCase) + singleOf(::StoreUsersUseCase) + singleOf(::AccountUseCaseImpl) bind AccountUseCase::class singleOf(::GetCurrentAccountUseCase) } diff --git a/feature/auth/src/main/kotlin/dev/meloda/fast/auth/login/LoginViewModel.kt b/feature/auth/src/main/kotlin/dev/meloda/fast/auth/login/LoginViewModel.kt index c57aaf4d..f8227713 100644 --- a/feature/auth/src/main/kotlin/dev/meloda/fast/auth/login/LoginViewModel.kt +++ b/feature/auth/src/main/kotlin/dev/meloda/fast/auth/login/LoginViewModel.kt @@ -20,8 +20,8 @@ import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.db.AccountsRepository import dev.meloda.fast.data.processState import dev.meloda.fast.datastore.AppSettings +import dev.meloda.fast.domain.LoadUserByIdUseCase import dev.meloda.fast.domain.OAuthUseCase -import dev.meloda.fast.domain.UsersUseCase import dev.meloda.fast.model.database.AccountEntity import dev.meloda.fast.network.OAuthErrorDomain import kotlinx.coroutines.Dispatchers @@ -71,7 +71,7 @@ interface LoginViewModel { class LoginViewModelImpl( private val oAuthUseCase: OAuthUseCase, - private val usersUseCase: UsersUseCase, + private val loadUserByIdUseCase: LoadUserByIdUseCase, private val accountsRepository: AccountsRepository, private val loginValidator: LoginValidator, private val longPollController: LongPollController @@ -171,8 +171,8 @@ class LoginViewModelImpl( UserConfig.trustedHash = account.trustedHash } - usersUseCase.get( - userIds = null, + loadUserByIdUseCase( + userId = null, fields = VkConstants.USER_FIELDS, nomCase = null ).listenValue(viewModelScope) { state -> @@ -185,7 +185,7 @@ class LoginViewModelImpl( // TODO: 19/07/2024, Danil Nikolaev: show error? }, success = { response -> - val actualUserId = response.first().id + val actualUserId = requireNotNull(response).id currentAccount = currentAccount.copy(userId = actualUserId) @@ -245,8 +245,8 @@ class LoginViewModelImpl( return@processState } - usersUseCase.get( - userIds = listOf(userId), + loadUserByIdUseCase( + userId = userId, fields = VkConstants.USER_FIELDS, nomCase = null ) diff --git a/feature/profile/src/main/kotlin/dev/meloda/fast/profile/ProfileViewModel.kt b/feature/profile/src/main/kotlin/dev/meloda/fast/profile/ProfileViewModel.kt index 1e345cb9..24cccd5a 100644 --- a/feature/profile/src/main/kotlin/dev/meloda/fast/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/kotlin/dev/meloda/fast/profile/ProfileViewModel.kt @@ -8,7 +8,8 @@ import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.data.State import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.processState -import dev.meloda.fast.domain.UsersUseCase +import dev.meloda.fast.domain.GetLocalUserByIdUseCase +import dev.meloda.fast.domain.LoadUserByIdUseCase import dev.meloda.fast.model.BaseError import dev.meloda.fast.network.VkErrorCode import dev.meloda.fast.profile.model.ProfileScreenState @@ -21,7 +22,8 @@ interface ProfileViewModel { } class ProfileViewModelImpl( - private val usersUseCase: UsersUseCase + private val getLocalUserByIdUseCase: GetLocalUserByIdUseCase, + private val loadUserByIdUseCase: LoadUserByIdUseCase ) : ViewModel(), ProfileViewModel { override val screenState = MutableStateFlow(ProfileScreenState.EMPTY) @@ -32,7 +34,7 @@ class ProfileViewModelImpl( } private fun getLocalAccountInfo() { - usersUseCase.getLocalUser(UserConfig.userId) + getLocalUserByIdUseCase(UserConfig.userId) .listenValue(viewModelScope) { state -> state.processState( error = { error -> @@ -67,8 +69,8 @@ class ProfileViewModelImpl( } private fun loadAccountInfo() { - usersUseCase.get( - userIds = null, + loadUserByIdUseCase( + userId = null, fields = VkConstants.USER_FIELDS, nomCase = null ).listenValue(viewModelScope) { state -> @@ -77,7 +79,7 @@ class ProfileViewModelImpl( // TODO: 12/07/2024, Danil Nikolaev: if local info is null then show error view }, success = { response -> - val user = response.single() + val user = requireNotNull(response) screenState.setValue { old -> old.copy( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4845feba..99aeec42 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,8 +2,8 @@ minSdk = "24" targetSdk = "35" compileSdk = "35" -versionCode = "4" -versionName = "0.1.1" +versionCode = "5" +versionName = "0.1.2" agp = "8.5.2" converterMoshi = "2.11.0"