From e32fcb534311da26d2efca44226d7bf34a7da2a6 Mon Sep 17 00:00:00 2001 From: "hoc081098@gmail.com" Date: Sun, 13 Jul 2025 16:44:49 +0700 Subject: [PATCH 1/7] refactor: clean up compiler and misc XML configurations --- .idea/compiler.xml | 11 ----------- .idea/misc.xml | 2 ++ buildSrc/gradle/wrapper/gradle-wrapper.jar | Bin 43705 -> 43764 bytes 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index f0abae06..a2b45ebf 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -2,17 +2,6 @@ - - - - - - - - - - - diff --git a/.idea/misc.xml b/.idea/misc.xml index 26bac8c8..38975a4e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,3 +1,4 @@ + + diff --git a/buildSrc/gradle/wrapper/gradle-wrapper.jar b/buildSrc/gradle/wrapper/gradle-wrapper.jar index 9bbc975c742b298b441bfb90dbc124400a3751b9..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 642 zcmdmamFde>rVZJA^}0Q$xegf!xPEW^+5YDM%iT2bEgct9o+jH~+sJas#HZ=szO|** z=Pj=X_vx?W&DSwKck|WWn~hffsvnQ+42*W$b7b0$SCcOoZ`{W{^$^pk;4>8-A*-)$ z?n(Po`1$6Jn_u?t-L+tsPyZ2#X}8T6OS8pAU;kdgd+_Hw4z4TW0p9E!T+=f7-c&O% zFic^X{7^$?^Ho04eona9n#mGMxKhA=~8B%JN`M zMhm5wc-2v)$``sY$!Q`9xiU@DhI73ZxiGEKg>yIPs)NmWwMdF-ngLXpZSqV5ez36n zVkxF2rjrjWR+_xr6e6@_u@s~2uv{9vi*1pj2)BjFD+-%@&pRVP1f{O1glxTOp2-62Ph;v z`N1+vCd)9ea)af*Ol1*JCfnp$%Uu}%OuoN7g2}3C@`L5FlP#(sA=|h@iixuZC?qp^ z=L$=v$ZoI}|87Wh=&h7udff{aieKr*l+zDp?pf)_bbRvUf>kn;HCDMXNlgbbo!QRK I1x7am0No)LiU0rr delta 584 zcmexzm1*ZyrVZJAexH5Moc8h7)w{^+t*dqJ%=yhh23L$9JpFV=_k`zJ-?Q4DI*eSe z+ES)HSrVnWLtJ&)lO%hRkV9zl5qqWRt0e;bb zPPo`)y?HTAyZI&u&X<|2$FDHCf4;!v8}p=?Tm`^F0`u(|1ttf~&t$qP3KUSD>@TJQ zRwJ}Pim6NzEc8KA6)e;S6gs8=7IIL8sQL*MYEuRYO;Uj<%3UbMbV&^&!Zvx+LKmjT z8Zch6rYP7Tw?$Hn(UTJwWiS=$f{lB(C=e*%usDV})0AQIK~sat=ND@+Gg*Pyij!rR z*fa02W|%BsV++>4W{DKDGSIUEHd2$P+8ct!RF+CHDowUuTEZOZ%rJSQv*qOXOSPDN zT|sP-$p*_3ncsWB*qoD7JQcyZ9xan%cJP6Tb4-?AZpr*F6v98hoNaPJm@HV`yya5N z))6pqFXn@}P(3T0nEzM8*c_9KtE9o|_pFd&K35GBXP^9Kg(b6GH-z8S4GDzIl~T+b zdLd#meKKHu$5u))8cu$=GKINkGDPOUD)!0$C(BH(U!}!-e;Q0ok8Sc?V1zRO04>ts AA^-pY From 65a05f1489a23d3daadf9ad28fb861795ad120dd Mon Sep 17 00:00:00 2001 From: "hoc081098@gmail.com" Date: Sun, 13 Jul 2025 16:49:23 +0700 Subject: [PATCH 2/7] refactor: rename getUsers to observeUsers for clarity and consistency --- .idea/kotlinc.xml | 2 +- .../com/hoc/flowmvi/core/selfReference.kt | 3 ++- .../hoc/flowmvi/data/UserRepositoryImpl.kt | 2 +- .../data/UserRepositoryImplRealAPITest.kt | 4 ++-- .../flowmvi/data/UserRepositoryImplTest.kt | 12 +++++----- .../com/hoc/flowmvi/domain/DomainModule.kt | 4 ++-- .../domain/repository/UserRepository.kt | 2 +- ...UsersUseCase.kt => ObserveUsersUseCase.kt} | 4 ++-- .../com/hoc/flowmvi/domain/UseCaseTest.kt | 22 +++++++++---------- .../java/com/hoc/flowmvi/ui/main/MainVM.kt | 6 ++--- .../com/hoc/flowmvi/ui/main/MainVMTest.kt | 6 ++--- 11 files changed, 34 insertions(+), 33 deletions(-) rename domain/src/main/java/com/hoc/flowmvi/domain/usecase/{GetUsersUseCase.kt => ObserveUsersUseCase.kt} (86%) diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 52631507..5e62b5a2 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -7,6 +7,6 @@ - \ No newline at end of file diff --git a/core/src/main/java/com/hoc/flowmvi/core/selfReference.kt b/core/src/main/java/com/hoc/flowmvi/core/selfReference.kt index dd109ee5..b526f31e 100644 --- a/core/src/main/java/com/hoc/flowmvi/core/selfReference.kt +++ b/core/src/main/java/com/hoc/flowmvi/core/selfReference.kt @@ -11,7 +11,8 @@ import kotlin.reflect.KProperty value class SelfReference( val value: T, ) : ReadOnlyProperty { - override fun getValue( + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun getValue( thisRef: Any?, property: KProperty<*>, ): T = value diff --git a/data/src/main/java/com/hoc/flowmvi/data/UserRepositoryImpl.kt b/data/src/main/java/com/hoc/flowmvi/data/UserRepositoryImpl.kt index 9fae3d28..e0d8061f 100644 --- a/data/src/main/java/com/hoc/flowmvi/data/UserRepositoryImpl.kt +++ b/data/src/main/java/com/hoc/flowmvi/data/UserRepositoryImpl.kt @@ -80,7 +80,7 @@ internal class UserRepositoryImpl( .first() @OptIn(FlowExtPreview::class) - override fun getUsers() = + override fun observeUsers() = changesFlow .onEach { Timber.d("[USER_REPO] Change=$it") } .scanWith(::getUsersFromRemoteWithRetry) { acc, change -> diff --git a/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplRealAPITest.kt b/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplRealAPITest.kt index 115dd5cf..c87eb7ca 100644 --- a/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplRealAPITest.kt +++ b/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplRealAPITest.kt @@ -56,12 +56,12 @@ class UserRepositoryImplRealAPITest : KoinTest { private val userRepo by inject() @Test - fun getUsers() = + fun observeUsers() = runBlocking { kotlin.runCatching { val result = userRepo - .getUsers() + .observeUsers() .first() assertTrue(result.isRight()) assertTrue(result.rightValueOrThrow.isNotEmpty()) diff --git a/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplTest.kt b/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplTest.kt index 15172f3a..327f9947 100644 --- a/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplTest.kt +++ b/data/src/test/java/com/hoc/flowmvi/data/UserRepositoryImplTest.kt @@ -285,7 +285,7 @@ class UserRepositoryImplTest { } @Test - fun test_getUsers_withApiCallSuccess_emitsInitial() = + fun test_observeUsers_withApiCallSuccess_emitsInitial() = runTest { coEvery { userApiService.getUsers() } returns USER_RESPONSES every { responseToDomain(any()) } returnsMany VALID_NES_USERS @@ -293,7 +293,7 @@ class UserRepositoryImplTest { val events = mutableListOf>>() val job = launch(start = CoroutineStart.UNDISPATCHED) { - repo.getUsers().toList(events) + repo.observeUsers().toList(events) } delay(5_000) job.cancel() @@ -313,7 +313,7 @@ class UserRepositoryImplTest { } @Test - fun test_getUsers_withApiCallError_rethrows() = + fun test_observeUsers_withApiCallError_rethrows() = runTest { coEvery { userApiService.getUsers() } throws IOException() every { errorMapper(ofType()) } returns UserError.NetworkError @@ -321,7 +321,7 @@ class UserRepositoryImplTest { val events = mutableListOf>>() val job = launch(start = CoroutineStart.UNDISPATCHED) { - repo.getUsers().toList(events) + repo.observeUsers().toList(events) } delay(20_000) job.cancel() @@ -337,7 +337,7 @@ class UserRepositoryImplTest { } @Test - fun test_getUsers_withApiCallSuccess_emitsInitialAndUpdatedUsers() = + fun test_observeUsers_withApiCallSuccess_emitsInitialAndUpdatedUsers() = runTest { val user = USERS.last() val userResponse = USER_RESPONSES.last() @@ -352,7 +352,7 @@ class UserRepositoryImplTest { val events = mutableListOf>>() val job = launch(start = CoroutineStart.UNDISPATCHED) { - repo.getUsers().toList(events) + repo.observeUsers().toList(events) } repo.add(user) repo.remove(user) diff --git a/domain/src/main/java/com/hoc/flowmvi/domain/DomainModule.kt b/domain/src/main/java/com/hoc/flowmvi/domain/DomainModule.kt index e8aa9b27..399dc2ad 100644 --- a/domain/src/main/java/com/hoc/flowmvi/domain/DomainModule.kt +++ b/domain/src/main/java/com/hoc/flowmvi/domain/DomainModule.kt @@ -1,7 +1,7 @@ package com.hoc.flowmvi.domain import com.hoc.flowmvi.domain.usecase.AddUserUseCase -import com.hoc.flowmvi.domain.usecase.GetUsersUseCase +import com.hoc.flowmvi.domain.usecase.ObserveUsersUseCase import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase import com.hoc.flowmvi.domain.usecase.SearchUsersUseCase @@ -11,7 +11,7 @@ import org.koin.dsl.module @JvmField val domainModule = module { - factoryOf(::GetUsersUseCase) + factoryOf(::ObserveUsersUseCase) factoryOf(::RefreshGetUsersUseCase) diff --git a/domain/src/main/java/com/hoc/flowmvi/domain/repository/UserRepository.kt b/domain/src/main/java/com/hoc/flowmvi/domain/repository/UserRepository.kt index acb9843e..25339fdc 100644 --- a/domain/src/main/java/com/hoc/flowmvi/domain/repository/UserRepository.kt +++ b/domain/src/main/java/com/hoc/flowmvi/domain/repository/UserRepository.kt @@ -6,7 +6,7 @@ import com.hoc.flowmvi.domain.model.UserError import kotlinx.coroutines.flow.Flow interface UserRepository { - fun getUsers(): Flow>> + fun observeUsers(): Flow>> suspend fun refresh(): Either diff --git a/domain/src/main/java/com/hoc/flowmvi/domain/usecase/GetUsersUseCase.kt b/domain/src/main/java/com/hoc/flowmvi/domain/usecase/ObserveUsersUseCase.kt similarity index 86% rename from domain/src/main/java/com/hoc/flowmvi/domain/usecase/GetUsersUseCase.kt rename to domain/src/main/java/com/hoc/flowmvi/domain/usecase/ObserveUsersUseCase.kt index 7ac40b8c..e1d0a83b 100644 --- a/domain/src/main/java/com/hoc/flowmvi/domain/usecase/GetUsersUseCase.kt +++ b/domain/src/main/java/com/hoc/flowmvi/domain/usecase/ObserveUsersUseCase.kt @@ -6,8 +6,8 @@ import com.hoc.flowmvi.domain.model.UserError import com.hoc.flowmvi.domain.repository.UserRepository import kotlinx.coroutines.flow.Flow -class GetUsersUseCase( +class ObserveUsersUseCase( private val userRepository: UserRepository, ) { - operator fun invoke(): Flow>> = userRepository.getUsers() + operator fun invoke(): Flow>> = userRepository.observeUsers() } diff --git a/domain/src/test/java/com/hoc/flowmvi/domain/UseCaseTest.kt b/domain/src/test/java/com/hoc/flowmvi/domain/UseCaseTest.kt index 2a1a2597..00198152 100644 --- a/domain/src/test/java/com/hoc/flowmvi/domain/UseCaseTest.kt +++ b/domain/src/test/java/com/hoc/flowmvi/domain/UseCaseTest.kt @@ -6,7 +6,7 @@ import com.hoc.flowmvi.domain.model.User import com.hoc.flowmvi.domain.model.UserError import com.hoc.flowmvi.domain.repository.UserRepository import com.hoc.flowmvi.domain.usecase.AddUserUseCase -import com.hoc.flowmvi.domain.usecase.GetUsersUseCase +import com.hoc.flowmvi.domain.usecase.ObserveUsersUseCase import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase import com.hoc.flowmvi.domain.usecase.SearchUsersUseCase @@ -60,7 +60,7 @@ class UseCaseTest { val coroutineRule = TestCoroutineDispatcherRule() private lateinit var userRepository: UserRepository - private lateinit var getUsersUseCase: GetUsersUseCase + private lateinit var observeUsersUseCase: ObserveUsersUseCase private lateinit var refreshUseCase: RefreshGetUsersUseCase private lateinit var removeUserUseCase: RemoveUserUseCase private lateinit var addUserUseCase: AddUserUseCase @@ -72,7 +72,7 @@ class UseCaseTest { fun setup() { userRepository = mockk() - getUsersUseCase = GetUsersUseCase(userRepository) + observeUsersUseCase = ObserveUsersUseCase(userRepository) refreshUseCase = RefreshGetUsersUseCase(userRepository) removeUserUseCase = RemoveUserUseCase(userRepository) addUserUseCase = AddUserUseCase(userRepository) @@ -86,25 +86,25 @@ class UseCaseTest { } @Test - fun test_getUsersUseCase_whenSuccess_emitsUsers() = + fun test_observeUsersUseCase_whenSuccess_emitsUsers() = runTest { val usersRight = USERS.right() - every { userRepository.getUsers() } returns flowOf(usersRight) + every { userRepository.observeUsers() } returns flowOf(usersRight) - val result = getUsersUseCase() + val result = observeUsersUseCase() - verify { userRepository.getUsers() } + verify { userRepository.observeUsers() } assertEquals(usersRight, result.first()) } @Test - fun test_getUsersUseCase_whenError_throwsError() = + fun test_observeUsersUseCase_whenError_throwsError() = runTest { - every { userRepository.getUsers() } returns flowOf(errorLeft) + every { userRepository.observeUsers() } returns flowOf(errorLeft) - val result = getUsersUseCase() + val result = observeUsersUseCase() - verify { userRepository.getUsers() } + verify { userRepository.observeUsers() } assertEquals(errorLeft, result.first()) } diff --git a/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt b/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt index 660f3944..48b67e48 100644 --- a/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt +++ b/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt @@ -3,7 +3,7 @@ package com.hoc.flowmvi.ui.main import androidx.lifecycle.viewModelScope import arrow.core.flatMap import com.hoc.flowmvi.core.selfReferenced -import com.hoc.flowmvi.domain.usecase.GetUsersUseCase +import com.hoc.flowmvi.domain.usecase.ObserveUsersUseCase import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase import com.hoc.flowmvi.mvi_base.AbstractMviViewModel @@ -33,7 +33,7 @@ import timber.log.Timber @FlowPreview @ExperimentalCoroutinesApi class MainVM( - private val getUsersUseCase: GetUsersUseCase, + private val observeUsersUseCase: ObserveUsersUseCase, private val refreshGetUsers: RefreshGetUsersUseCase, private val removeUser: RemoveUserUseCase, ) : AbstractMviViewModel() { @@ -78,7 +78,7 @@ class MainVM( //region Processors private fun Flow.toUserChangeFlow(): Flow { val userChanges = - defer(getUsersUseCase::invoke) + defer { observeUsersUseCase() } .onEach { either -> Timber.tag(logTag).d("Emit users.size=${either.map { it.size }}") } .map { result -> result.fold( diff --git a/feature-main/src/test/java/com/hoc/flowmvi/ui/main/MainVMTest.kt b/feature-main/src/test/java/com/hoc/flowmvi/ui/main/MainVMTest.kt index 349fee5f..e082203f 100644 --- a/feature-main/src/test/java/com/hoc/flowmvi/ui/main/MainVMTest.kt +++ b/feature-main/src/test/java/com/hoc/flowmvi/ui/main/MainVMTest.kt @@ -4,7 +4,7 @@ import arrow.core.left import arrow.core.right import com.hoc.flowmvi.domain.model.User import com.hoc.flowmvi.domain.model.UserError -import com.hoc.flowmvi.domain.usecase.GetUsersUseCase +import com.hoc.flowmvi.domain.usecase.ObserveUsersUseCase import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase import com.hoc.flowmvi.mvi_testing.BaseMviViewModelTest @@ -40,7 +40,7 @@ class MainVMTest : MainVM, >() { private lateinit var vm: MainVM - private lateinit var getUserUseCase: GetUsersUseCase + private lateinit var getUserUseCase: ObserveUsersUseCase private lateinit var refreshGetUsersUseCase: RefreshGetUsersUseCase private lateinit var removeUser: RemoveUserUseCase @@ -53,7 +53,7 @@ class MainVMTest : vm = MainVM( - getUsersUseCase = getUserUseCase, + observeUsersUseCase = getUserUseCase, refreshGetUsers = refreshGetUsersUseCase, removeUser = removeUser, ) From cfbb06e3112ef29cdf555c0a0b486d21d1fbbc45 Mon Sep 17 00:00:00 2001 From: "hoc081098@gmail.com" Date: Sun, 13 Jul 2025 16:53:55 +0700 Subject: [PATCH 3/7] refactor: update coroutine dispatcher checks and improve code style settings --- .idea/codeStyles/Project.xml | 35 +++++++++++++++++++ .../debugCheckImmediateMainDispatcher.kt | 17 +++++---- .../flowmvi/mvi_base/AbstractMviViewModel.kt | 7 ++-- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1cae6040..f649736f 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,5 +1,40 @@ + + +