diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 00000000..0dd4b354 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460d..00000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a8ca5d97..0f367f9a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -52,7 +52,7 @@ dependencies { implementation(featureMain) implementation(featureAdd) - implementation(deps.jetbrains.coroutinesAndroid) + implementation(deps.coroutines.android) implementation(deps.koin.android) testImplementation(deps.test.junit) diff --git a/build.gradle.kts b/build.gradle.kts index f05f118e..1b48d85e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,17 +1,17 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - val kotlinVersion by extra("1.4.0-rc") repositories { google() - jcenter() - maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") + mavenCentral() gradlePluginPortal() } dependencies { - classpath("com.android.tools.build:gradle:4.0.1") + classpath("com.android.tools.build:gradle:4.0.2") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") - classpath("com.diffplug.spotless:spotless-plugin-gradle:5.3.0") + classpath("com.diffplug.spotless:spotless-plugin-gradle:5.10.0") } } @@ -61,19 +61,20 @@ subprojects { } allprojects { - tasks.withType { + tasks.withType { kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() - sourceCompatibility = JavaVersion.VERSION_1_8.toString() - targetCompatibility = JavaVersion.VERSION_1_8.toString() + useIR = true + + val version = JavaVersion.VERSION_1_8.toString() + jvmTarget = version + sourceCompatibility = version + targetCompatibility = version } } repositories { google() - jcenter() mavenCentral() - maven(url = "https://dl.bintray.com/kotlin/kotlin-eap") } } diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt index f41e1dc6..7c9f9804 100644 --- a/buildSrc/src/main/kotlin/deps.kt +++ b/buildSrc/src/main/kotlin/deps.kt @@ -5,8 +5,8 @@ import org.gradle.kotlin.dsl.project import org.gradle.plugin.use.PluginDependenciesSpec import org.gradle.plugin.use.PluginDependencySpec -const val ktlintVersion = "0.38.1" -const val kotlinVersion = "1.4.10" +const val ktlintVersion = "0.41.0" +const val kotlinVersion = "1.5.0-M1" object appConfig { const val applicationId = "com.hoc.flowmvi" @@ -22,16 +22,16 @@ object appConfig { object deps { object androidx { - const val appCompat = "androidx.appcompat:appcompat:1.3.0-alpha02" - const val coreKtx = "androidx.core:core-ktx:1.5.0-alpha02" - const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.0.1" - const val recyclerView = "androidx.recyclerview:recyclerview:1.2.0-alpha05" + const val appCompat = "androidx.appcompat:appcompat:1.3.0-rc01" + const val coreKtx = "androidx.core:core-ktx:1.6.0-alpha01" + const val constraintLayout = "androidx.constraintlayout:constraintlayout:2.1.0-beta01" + const val recyclerView = "androidx.recyclerview:recyclerview:1.2.0-rc01" const val swipeRefreshLayout = "androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01" - const val material = "com.google.android.material:material:1.3.0-alpha02" + const val material = "com.google.android.material:material:1.4.0-alpha01" } object lifecycle { - private const val version = "2.3.0-beta01" + private const val version = "2.4.0-alpha01" const val viewModelKtx = "androidx.lifecycle:lifecycle-viewmodel-ktx:$version" // viewModelScope const val runtimeKtx = "androidx.lifecycle:lifecycle-runtime-ktx:$version" // lifecycleScope @@ -41,26 +41,25 @@ object deps { object squareup { const val retrofit = "com.squareup.retrofit2:retrofit:2.9.0" const val converterMoshi = "com.squareup.retrofit2:converter-moshi:2.9.0" - const val loggingInterceptor = "com.squareup.okhttp3:logging-interceptor:4.8.1" - const val moshiKotlin = "com.squareup.moshi:moshi-kotlin:1.10.0" + const val loggingInterceptor = "com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2" + const val moshiKotlin = "com.squareup.moshi:moshi-kotlin:1.11.0" } - object jetbrains { - private const val version = "1.4.0" + object coroutines { + private const val version = "1.4.3" - const val coroutinesCore = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version" - const val coroutinesAndroid = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version" + const val core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version" + const val android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version" } object koin { - private const val version = "2.2.2" + private const val version = "3.0.1-beta-2" - const val androidXViewModel = "org.koin:koin-androidx-viewmodel:$version" - const val core = "org.koin:koin-core:$version" - const val android = "org.koin:koin-android:$version" + const val core = "io.insert-koin:koin-core:$version" + const val android = "io.insert-koin:koin-android:$version" } - const val coil = "io.coil-kt:coil:1.0.0" + const val coil = "io.coil-kt:coil:1.1.1" object test { const val junit = "junit:junit:4.13" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 31353c20..0770677d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -34,8 +34,8 @@ android { } dependencies { - implementation(deps.jetbrains.coroutinesCore) - implementation(deps.jetbrains.coroutinesAndroid) + implementation(deps.coroutines.core) + implementation(deps.coroutines.android) implementation(deps.androidx.coreKtx) implementation(deps.androidx.swipeRefreshLayout) diff --git a/core/src/main/java/com/hoc/flowmvi/core/Flow+LaunchIn.kt b/core/src/main/java/com/hoc/flowmvi/core/Flow+LaunchIn.kt deleted file mode 100644 index 69d305d7..00000000 --- a/core/src/main/java/com/hoc/flowmvi/core/Flow+LaunchIn.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.hoc.flowmvi.core - -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.launchIn - -fun Flow.launchWhenStartedUntilStopped(owner: LifecycleOwner) { - if (owner.lifecycle.currentState == Lifecycle.State.DESTROYED) { - // ignore - return - } - owner.lifecycle.addObserver(LifecycleBoundObserver(this)) -} - -private class LifecycleBoundObserver(private val flow: Flow<*>) : DefaultLifecycleObserver { - private var job: Job? = null - - override fun onStart(owner: LifecycleOwner) { - job = flow.launchIn(owner.lifecycleScope) - } - - override fun onStop(owner: LifecycleOwner) { - cancelJob() - } - - override fun onDestroy(owner: LifecycleOwner) { - super.onDestroy(owner) - owner.lifecycle.removeObserver(this) - cancelJob() - } - - @Suppress("NOTHING_TO_INLINE") - private inline fun cancelJob() { - job?.cancel() - job = null - } -} diff --git a/data/build.gradle.kts b/data/build.gradle.kts index d32375fe..58f18ee4 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -37,7 +37,7 @@ dependencies { implementation(core) implementation(domain) - implementation(deps.jetbrains.coroutinesCore) + implementation(deps.coroutines.core) implementation(deps.squareup.retrofit) implementation(deps.squareup.moshiKotlin) diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index 6cc7bff5..45c82b6d 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -3,6 +3,6 @@ plugins { } dependencies { - implementation(deps.jetbrains.coroutinesCore) + implementation(deps.coroutines.core) implementation(deps.koin.core) } diff --git a/feature-add/build.gradle.kts b/feature-add/build.gradle.kts index 0d7f4a7f..f4ca0597 100644 --- a/feature-add/build.gradle.kts +++ b/feature-add/build.gradle.kts @@ -48,6 +48,6 @@ dependencies { implementation(deps.androidx.constraintLayout) implementation(deps.androidx.material) - implementation(deps.jetbrains.coroutinesCore) - implementation(deps.koin.androidXViewModel) + implementation(deps.coroutines.core) + implementation(deps.koin.android) } diff --git a/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddActivity.kt b/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddActivity.kt index 9c1decce..89f89272 100644 --- a/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddActivity.kt +++ b/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddActivity.kt @@ -7,12 +7,13 @@ import android.util.Log import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isInvisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.transition.AutoTransition import androidx.transition.TransitionManager import com.hoc.flowmvi.core.clicks import com.hoc.flowmvi.core.firstChange -import com.hoc.flowmvi.core.launchWhenStartedUntilStopped import com.hoc.flowmvi.core.navigator.IntentProviders import com.hoc.flowmvi.core.textChanges import com.hoc.flowmvi.core.toast @@ -24,14 +25,13 @@ 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.scope.emptyState +import org.koin.androidx.viewmodel.ext.android.stateViewModel import kotlin.LazyThreadSafetyMode.NONE @FlowPreview @ExperimentalCoroutinesApi class AddActivity : AppCompatActivity() { - private val addVM by viewModel(state = emptyState()) + private val addVM by stateViewModel() private val addBinding by lazy(NONE) { ActivityAddBinding.inflate(layoutInflater) } override fun onCreate(savedInstanceState: Bundle?) { @@ -54,12 +54,14 @@ class AddActivity : AppCompatActivity() { // observe view model addVM.viewState .onEach { render(it) } - .launchWhenStartedUntilStopped(this) + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .launchIn(lifecycleScope) // observe single event addVM.singleEvent .onEach { handleSingleEvent(it) } - .launchWhenStartedUntilStopped(this) + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .launchIn(lifecycleScope) // pass view intent to view model intents() diff --git a/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddModule.kt b/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddModule.kt index 0c1c33da..5fb56d91 100644 --- a/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddModule.kt +++ b/feature-add/src/main/java/com/hoc/flowmvi/ui/add/AddModule.kt @@ -9,10 +9,10 @@ import org.koin.dsl.module @ExperimentalCoroutinesApi @FlowPreview val addModule = module { - viewModel { + viewModel { params -> AddVM( addUser = get(), - savedStateHandle = it.get(), + savedStateHandle = params.get(), ) } diff --git a/feature-main/build.gradle.kts b/feature-main/build.gradle.kts index 6ec302c8..1505c100 100644 --- a/feature-main/build.gradle.kts +++ b/feature-main/build.gradle.kts @@ -50,7 +50,7 @@ dependencies { implementation(deps.androidx.swipeRefreshLayout) implementation(deps.androidx.material) - implementation(deps.jetbrains.coroutinesCore) - implementation(deps.koin.androidXViewModel) + implementation(deps.coroutines.core) + implementation(deps.koin.android) implementation(deps.coil) } diff --git a/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainActivity.kt b/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainActivity.kt index 917445db..f2bef2ac 100644 --- a/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainActivity.kt +++ b/feature-main/src/main/java/com/hoc/flowmvi/ui/main/MainActivity.kt @@ -6,6 +6,8 @@ import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper @@ -13,7 +15,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.hoc.flowmvi.core.SwipeLeftToDeleteCallback import com.hoc.flowmvi.core.clicks -import com.hoc.flowmvi.core.launchWhenStartedUntilStopped import com.hoc.flowmvi.core.navigator.Navigator import com.hoc.flowmvi.core.refreshes import com.hoc.flowmvi.core.safeOffer @@ -86,12 +87,14 @@ class MainActivity : AppCompatActivity() { // observe view model mainVM.viewState .onEach { render(it) } - .launchWhenStartedUntilStopped(this) + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .launchIn(lifecycleScope) // observe single event mainVM.singleEvent .onEach { handleSingleEvent(it) } - .launchWhenStartedUntilStopped(this) + .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + .launchIn(lifecycleScope) // pass view intent to view model intents()