Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions app/src/main/java/com/hoc/flowmvi/core/CoreModule.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.hoc.flowmvi.core

import com.hoc.flowmvi.core.dispatchers.CoroutineDispatchers
import com.hoc.flowmvi.core.dispatchers.AppCoroutineDispatchers
import com.hoc.flowmvi.core_ui.navigator.Navigator
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module

@JvmField
val coreModule = module {
single<CoroutineDispatchers> { DefaultCoroutineDispatchers() }
singleOf(::DefaultAppCoroutineDispatchers) { bind<AppCoroutineDispatchers>() }

single<Navigator> { NavigatorImpl(add = get(), search = get()) }
singleOf(::NavigatorImpl) { bind<Navigator>() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.hoc.flowmvi.core

import com.hoc.flowmvi.core.dispatchers.AppCoroutineDispatchers
import kotlinx.coroutines.Dispatchers

internal class DefaultAppCoroutineDispatchers : AppCoroutineDispatchers {
override val main get() = Dispatchers.Main
override val mainImmediate get() = Dispatchers.Main.immediate
override val io get() = Dispatchers.IO
}

This file was deleted.

12 changes: 8 additions & 4 deletions app/src/test/java/com/hoc/flowmvi/CheckModulesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.hoc.flowmvi
import androidx.lifecycle.SavedStateHandle
import com.hoc.flowmvi.test_utils.TestCoroutineDispatcherRule
import io.mockk.every
import io.mockk.mockkClass
import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import org.junit.Rule
Expand All @@ -22,12 +22,16 @@ import kotlin.time.ExperimentalTime
class CheckModulesTest : AutoCloseKoinTest() {
@get:Rule
val mockProvider = MockProviderRule.create { clazz ->
mockkClass(clazz).also { o ->
if (clazz == SavedStateHandle::class) {
every { (o as SavedStateHandle).get<Any?>(any()) } returns null
when (clazz) {
SavedStateHandle::class -> {
mockk<SavedStateHandle>() {
every { get<Any?>(any()) } returns null
}
}
else -> error("Unknown class: $clazz")
}
}

@get:Rule
val coroutineRule = TestCoroutineDispatcherRule()

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/deps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ object deps {
}

object koin {
private const val version = "3.2.0-beta-1"
private const val version = "3.2.0"

const val core = "io.insert-koin:koin-core:$version"
const val android = "io.insert-koin:koin-android:$version"
Expand Down Expand Up @@ -90,7 +90,7 @@ object deps {
}
}

const val mockk = "io.mockk:mockk:1.12.3"
const val mockk = "io.mockk:mockk:1.12.4"
const val kotlinJUnit = "org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package com.hoc.flowmvi.core.dispatchers

import kotlinx.coroutines.CoroutineDispatcher

interface CoroutineDispatchers {
interface AppCoroutineDispatchers {
val main: CoroutineDispatcher
val mainImmediate: CoroutineDispatcher
val io: CoroutineDispatcher
}
10 changes: 6 additions & 4 deletions data/src/main/java/com/hoc/flowmvi/data/DataModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,24 @@ import kotlinx.coroutines.FlowPreview
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.HttpLoggingInterceptor.Level
import org.koin.core.module.dsl.singleOf
import org.koin.core.qualifier.named
import org.koin.dsl.module
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.util.concurrent.TimeUnit
import kotlin.time.ExperimentalTime

val BASE_URL_QUALIFIER = named("BASE_URL")
internal val BASE_URL_QUALIFIER = named("BASE_URL")
internal val ERROR_RESPONSE_JSON_ADAPTER = named("ERROR_RESPONSE_JSON_ADAPTER")

@JvmField
@FlowPreview
@ExperimentalStdlibApi
@ExperimentalTime
@ExperimentalCoroutinesApi
val dataModule = module {
single { UserApiService(retrofit = get()) }
singleOf(UserApiService::invoke)

single {
provideRetrofit(
Expand All @@ -49,9 +51,9 @@ val dataModule = module {

factory { UserDomainToUserBodyMapper() }

factory { get<Moshi>().adapter<ErrorResponse>() }
factory(ERROR_RESPONSE_JSON_ADAPTER) { get<Moshi>().adapter<ErrorResponse>() }

factory { UserErrorMapper(errorResponseJsonAdapter = get()) }
factory { UserErrorMapper(get(ERROR_RESPONSE_JSON_ADAPTER)) }

single<UserRepository> {
UserRepositoryImpl(
Expand Down
4 changes: 2 additions & 2 deletions data/src/main/java/com/hoc/flowmvi/data/UserRepositoryImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import arrow.core.leftWiden
import arrow.core.right
import arrow.core.valueOr
import com.hoc.flowmvi.core.Mapper
import com.hoc.flowmvi.core.dispatchers.CoroutineDispatchers
import com.hoc.flowmvi.core.dispatchers.AppCoroutineDispatchers
import com.hoc.flowmvi.data.remote.UserApiService
import com.hoc.flowmvi.data.remote.UserBody
import com.hoc.flowmvi.data.remote.UserResponse
Expand Down Expand Up @@ -39,7 +39,7 @@ import arrow.core.Either.Companion.catch as catchEither
@ExperimentalCoroutinesApi
internal class UserRepositoryImpl(
private val userApiService: UserApiService,
private val dispatchers: CoroutineDispatchers,
private val dispatchers: AppCoroutineDispatchers,
private val responseToDomain: Mapper<UserResponse, ValidatedNel<UserValidationError, User>>,
private val domainToBody: Mapper<User, UserBody>,
private val errorMapper: Mapper<Throwable, UserError>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.hoc.flowmvi.data

import android.util.Log
import com.hoc.flowmvi.core.dispatchers.CoroutineDispatchers
import com.hoc.flowmvi.core.dispatchers.AppCoroutineDispatchers
import com.hoc.flowmvi.domain.repository.UserRepository
import com.hoc.flowmvi.test_utils.getOrThrow
import kotlinx.coroutines.CoroutineDispatcher
Expand Down Expand Up @@ -38,10 +38,11 @@ class UserRepositoryImplRealAPITest : KoinTest {
modules(
dataModule,
module {
factory<CoroutineDispatchers> {
object : CoroutineDispatchers {
factory<AppCoroutineDispatchers> {
object : AppCoroutineDispatchers {
override val main: CoroutineDispatcher get() = Main
override val io: CoroutineDispatcher get() = IO
override val mainImmediate: CoroutineDispatcher get() = Main.immediate
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import com.hoc.flowmvi.data.remote.UserResponse
import com.hoc.flowmvi.domain.model.User
import com.hoc.flowmvi.domain.model.UserError
import com.hoc.flowmvi.domain.model.UserValidationError
import com.hoc.flowmvi.test_utils.TestAppCoroutineDispatchers
import com.hoc.flowmvi.test_utils.TestCoroutineDispatcherRule
import com.hoc.flowmvi.test_utils.TestDispatchers
import com.hoc.flowmvi.test_utils.getOrThrow
import com.hoc.flowmvi.test_utils.leftOrThrow
import com.hoc.flowmvi.test_utils.valueOrThrow
Expand Down Expand Up @@ -121,7 +121,7 @@ class UserRepositoryImplTest {

repo = UserRepositoryImpl(
userApiService = userApiService,
dispatchers = TestDispatchers(coroutineRule.testDispatcher),
dispatchers = TestAppCoroutineDispatchers(coroutineRule.testDispatcher),
responseToDomain = responseToDomain,
domainToBody = domainToBody,
errorMapper = errorMapper
Expand Down
11 changes: 6 additions & 5 deletions domain/src/main/java/com/hoc/flowmvi/domain/DomainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ import com.hoc.flowmvi.domain.usecase.GetUsersUseCase
import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase
import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase
import com.hoc.flowmvi.domain.usecase.SearchUsersUseCase
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.module

@JvmField
val domainModule = module {
factory { GetUsersUseCase(userRepository = get()) }
factoryOf(::GetUsersUseCase)

factory { RefreshGetUsersUseCase(userRepository = get()) }
factoryOf(::RefreshGetUsersUseCase)

factory { RemoveUserUseCase(userRepository = get()) }
factoryOf(::RemoveUserUseCase)

factory { AddUserUseCase(userRepository = get()) }
factoryOf(::AddUserUseCase)

factory { SearchUsersUseCase(userRepository = get()) }
factoryOf(::SearchUsersUseCase)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.androidx.viewmodel.ext.android.stateViewModel
import timber.log.Timber

@ExperimentalCoroutinesApi
class AddActivity :
AbstractMviActivity<ViewIntent, ViewState, SingleEvent, AddVM>(R.layout.activity_add) {
override val vm by viewModel<AddVM>()
override val vm by stateViewModel<AddVM>()
private val addBinding by viewBinding<ActivityAddBinding>()

override fun onOptionsItemSelected(item: MenuItem): Boolean {
Expand Down
13 changes: 5 additions & 8 deletions feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ package com.hoc.flowmvi.ui.add

import com.hoc.flowmvi.core_ui.navigator.IntentProviders
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.module

@JvmField
@ExperimentalCoroutinesApi
val addModule = module {
viewModel { params ->
AddVM(
addUser = get(),
savedStateHandle = params.get(),
)
}
viewModelOf(::AddVM)

single<IntentProviders.Add> { AddActivity.IntentProvider() }
singleOf(AddActivity::IntentProvider) { bind<IntentProviders.Add>() }
}
4 changes: 3 additions & 1 deletion feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.hoc.flowmvi.ui.add
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import arrow.core.orNull
import com.hoc.flowmvi.core.dispatchers.AppCoroutineDispatchers
import com.hoc.flowmvi.domain.model.User
import com.hoc.flowmvi.domain.usecase.AddUserUseCase
import com.hoc.flowmvi.mvi_base.AbstractMviViewModel
Expand Down Expand Up @@ -33,7 +34,8 @@ import timber.log.Timber
class AddVM(
private val addUser: AddUserUseCase,
savedStateHandle: SavedStateHandle,
) : AbstractMviViewModel<ViewIntent, ViewState, SingleEvent>() {
appCoroutineDispatchers: AppCoroutineDispatchers,
) : AbstractMviViewModel<ViewIntent, ViewState, SingleEvent>(appCoroutineDispatchers) {

override val viewState: StateFlow<ViewState>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.hoc.flowmvi.domain.usecase.AddUserUseCase
import com.hoc.flowmvi.mvi_testing.BaseMviViewModelTest
import com.hoc.flowmvi.mvi_testing.mapRight
import com.hoc.flowmvi.mvi_testing.returnsWithDelay
import com.hoc.flowmvi.test_utils.TestAppCoroutineDispatchers
import com.hoc.flowmvi.test_utils.valueOrThrow
import io.mockk.coEvery
import io.mockk.coVerify
Expand Down Expand Up @@ -41,7 +42,8 @@ class AddVMTest : BaseMviViewModelTest<ViewIntent, ViewState, SingleEvent, AddVM

vm = AddVM(
addUser = addUser,
savedStateHandle = savedStateHandle
savedStateHandle = savedStateHandle,
appCoroutineDispatchers = TestAppCoroutineDispatchers(coroutineRule.testDispatcher)
)
}

Expand Down
10 changes: 2 additions & 8 deletions feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ package com.hoc.flowmvi.ui.main

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.dsl.module

@JvmField
@ExperimentalCoroutinesApi
@FlowPreview
val mainModule = module {
viewModel {
MainVM(
getUsersUseCase = get(),
refreshGetUsers = get(),
removeUser = get()
)
}
viewModelOf(::MainVM)
}
4 changes: 3 additions & 1 deletion feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainVM.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.hoc.flowmvi.ui.main

import androidx.lifecycle.viewModelScope
import arrow.core.flatMap
import com.hoc.flowmvi.core.dispatchers.AppCoroutineDispatchers
import com.hoc.flowmvi.domain.usecase.GetUsersUseCase
import com.hoc.flowmvi.domain.usecase.RefreshGetUsersUseCase
import com.hoc.flowmvi.domain.usecase.RemoveUserUseCase
Expand Down Expand Up @@ -36,7 +37,8 @@ class MainVM(
private val getUsersUseCase: GetUsersUseCase,
private val refreshGetUsers: RefreshGetUsersUseCase,
private val removeUser: RemoveUserUseCase,
) : AbstractMviViewModel<ViewIntent, ViewState, SingleEvent>() {
appCoroutineDispatchers: AppCoroutineDispatchers,
) : AbstractMviViewModel<ViewIntent, ViewState, SingleEvent>(appCoroutineDispatchers) {

override val viewState: StateFlow<ViewState>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.hoc.flowmvi.mvi_testing.BaseMviViewModelTest
import com.hoc.flowmvi.mvi_testing.delayEach
import com.hoc.flowmvi.mvi_testing.mapRight
import com.hoc.flowmvi.mvi_testing.returnsWithDelay
import com.hoc.flowmvi.test_utils.TestAppCoroutineDispatchers
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.coVerifySequence
Expand Down Expand Up @@ -54,6 +55,7 @@ class MainVMTest : BaseMviViewModelTest<
getUsersUseCase = getUserUseCase,
refreshGetUsers = refreshGetUsersUseCase,
removeUser = removeUser,
appCoroutineDispatchers = TestAppCoroutineDispatchers(coroutineRule.testDispatcher)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.androidx.viewmodel.ext.android.stateViewModel
import timber.log.Timber
import kotlin.time.ExperimentalTime

Expand All @@ -40,7 +40,7 @@ import kotlin.time.ExperimentalTime
class SearchActivity :
AbstractMviActivity<ViewIntent, ViewState, SingleEvent, SearchVM>(R.layout.activity_search) {
private val binding by viewBinding<ActivitySearchBinding>()
override val vm by viewModel<SearchVM>()
override val vm by stateViewModel<SearchVM>()

private val searchViewQueryTextEventChannel = Channel<SearchViewQueryTextEvent>()
private val searchAdapter = SearchAdapter()
Expand Down
Loading