diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index fb7f4a8..b589d56 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 5c30b7b..26b0f5e 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
-
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e7fc0e8..acd5749 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Mon May 30 19:20:45 BST 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/kompot/build.gradle b/kompot/build.gradle
index 577ad67..e9e30b9 100644
--- a/kompot/build.gradle
+++ b/kompot/build.gradle
@@ -13,6 +13,8 @@ android {
buildToolsVersion androidBuildToolsVersion
targetSdkVersion androidTargetSdkVersion
minSdkVersion androidMinSdkVersion
+
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
sourceSets {
@@ -39,10 +41,15 @@ android {
}
}
+tasks.withType(Test) {
+ javaLauncher.set(javaToolchains.launcherFor {
+ languageVersion.set(JavaLanguageVersion.of(11))
+ })
+}
+
dependencies {
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
api "com.google.dagger:dagger:$daggerVersion"
- api "com.revolut.recyclerkit:rxdiffadapter:$recyclerKitRxDiffAdapterVersion"
api "com.revolut.recyclerkit:delegates:$recyclerKitDelegatesVersion"
api "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
api "androidx.coordinatorlayout:coordinatorlayout:$coordinatorLayoutVersion"
@@ -66,6 +73,8 @@ dependencies {
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:$mockitoKotlinVersion"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
testImplementation "junit:junit:$junitVersion"
+ testImplementation "androidx.test:core-ktx:$androidxTestVersion"
+ testImplementation project(':kompot_coroutines_test')
testImplementation("org.robolectric:robolectric:$robolectricVersion") {
exclude group: "com.google.auto.service", module: "auto-service"
diff --git a/kompot/gradle.properties b/kompot/gradle.properties
index 3b9a921..a63b8fd 100644
--- a/kompot/gradle.properties
+++ b/kompot/gradle.properties
@@ -1,21 +1,5 @@
-#
-# Copyright (C) 2022 Revolut
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
POM_ARTIFACT_ID=kompot
-VERSION_NAME=0.0.2
+VERSION_NAME=0.0.3
POM_NAME=kompot
POM_PACKAGING=aar
GROUP=com.revolut.kompot
\ No newline at end of file
diff --git a/kompot/kompot_dependencies_versions.gradle b/kompot/kompot_dependencies_versions.gradle
index 91cd254..e242ce6 100644
--- a/kompot/kompot_dependencies_versions.gradle
+++ b/kompot/kompot_dependencies_versions.gradle
@@ -1,8 +1,8 @@
ext {
- androidBuildToolsVersion = '30.0.3'
- androidMinSdkVersion = 23
+ androidBuildToolsVersion = '33.0.2'
+ androidMinSdkVersion = 24
androidTargetSdkVersion = 31
- androidCompileSdkVersion = 31
+ androidCompileSdkVersion = 33
kotlinVersion = '1.6.10'
@@ -10,15 +10,15 @@ ext {
daggerVersion = '2.35.1'
- recyclerKitRxDiffAdapterVersion = '1.0.7'
- recyclerKitDecorationsVersion = '1.0.8'
- recyclerKitDelegatesVersion = '1.0.10'
+ recyclerKitDecorationsVersion = '1.1.0'
+ recyclerKitDelegatesVersion = '1.1.2'
- timberVersion = '4.7.1'
+ timberVersion = '5.0.1'
androidxCoreVersion = '1.7.0'
appCompatVersion = '1.1.0'
recyclerVersion = '1.1.0'
+ androidxTestVersion = '1.5.0'
constraintLayoutVersion = '1.1.3'
coordinatorLayoutVersion = '1.1.0'
@@ -27,7 +27,7 @@ ext {
junitVersion = '4.12'
junitJupiterVersion = '5.4.2'
junitVintageVersion = '5.4.2'
- mockitoVersion = '3.9.0'
+ mockitoVersion = '5.1.1'
mockitoKotlinVersion = '2.2.0'
robolectricVersion = '4.5'
diff --git a/kompot/src/main/kotlin/com/revolut/kompot/FeaturesRegistry.kt b/kompot/src/main/kotlin/com/revolut/kompot/FeaturesRegistry.kt
index f3dd741..fffa660 100644
--- a/kompot/src/main/kotlin/com/revolut/kompot/FeaturesRegistry.kt
+++ b/kompot/src/main/kotlin/com/revolut/kompot/FeaturesRegistry.kt
@@ -17,10 +17,13 @@
package com.revolut.kompot
import android.content.Context
+import com.revolut.kompot.common.ControllerDescriptor
+import com.revolut.kompot.common.ControllerHolder
+import com.revolut.kompot.common.IOData
import com.revolut.kompot.common.NavigationDestination
+import com.revolut.kompot.common.NavigationRequest
import com.revolut.kompot.navigable.Controller
import com.revolut.kompot.navigable.flow.BaseFlowModel
-import javax.inject.Inject
interface FeaturesRegistry {
fun clearFeatures(context: Context, signOut: Boolean)
@@ -37,9 +40,17 @@ interface FeaturesRegistry {
destination: NavigationDestination,
flowModel: BaseFlowModel<*, *, *>
): Controller
+
+ fun provideControllerOrThrow(
+ descriptor: ControllerDescriptor<*>,
+ ): ControllerHolder
+
+ suspend fun getDestinationOrThrow(
+ request: NavigationRequest
+ ): NavigationDestination
}
-class DefaultFeaturesRegistry @Inject constructor() : FeaturesRegistry {
+class DefaultFeaturesRegistry : FeaturesRegistry {
private val featureGateways: MutableList = mutableListOf()
private val featureHolders: MutableList = mutableListOf()
@@ -74,25 +85,25 @@ class DefaultFeaturesRegistry @Inject constructor() : FeaturesRegistry {
override fun getControllerOrThrow(
destination: NavigationDestination,
flowModel: BaseFlowModel<*, *, *>
- ): Controller {
- featureGateways.forEach { gateway ->
- val controller = gateway.getController(destination, flowModel)
- if (controller != null) {
- return controller
- }
+ ): Controller =
+ featureGateways.firstNotNullOfOrNull { gateway ->
+ gateway.getController(destination, flowModel)
+ } ?: error("Controller for $destination not found")
+
+ override fun provideControllerOrThrow(descriptor: ControllerDescriptor<*>): ControllerHolder =
+ featureGateways.firstNotNullOfOrNull { gateway ->
+ gateway.provideController(descriptor)
+ } ?: error("Controller for $descriptor not found")
+
+ override fun interceptDestination(destination: NavigationDestination): NavigationDestination? =
+ featureGateways.firstNotNullOfOrNull { gateway ->
+ gateway.interceptDestination(destination)
}
- throw IllegalStateException("Controller for $destination not found")
- }
- override fun interceptDestination(destination: NavigationDestination): NavigationDestination? {
- featureGateways.forEach { gateway ->
- val replacedDestination = gateway.interceptDestination(destination)
- if (replacedDestination != null) {
- return replacedDestination
- }
- }
- return null
- }
+ override suspend fun getDestinationOrThrow(request: NavigationRequest): NavigationDestination =
+ featureGateways.firstNotNullOfOrNull { gateway ->
+ gateway.getDestination(request)
+ } ?: error("Destination for $request not found")
}
interface FeatureApi
@@ -106,6 +117,9 @@ interface FeatureGateway : FeatureHolder {
fun interceptDestination(destination: NavigationDestination): NavigationDestination? = null
+ fun provideController(descriptor: ControllerDescriptor): ControllerHolder? = null
+
+ suspend fun getDestination(request: NavigationRequest): NavigationDestination? = null
}
interface FeatureHolder {
diff --git a/kompot/src/main/kotlin/com/revolut/kompot/KompotPlugin.kt b/kompot/src/main/kotlin/com/revolut/kompot/KompotPlugin.kt
index d41b1cb..22a220a 100644
--- a/kompot/src/main/kotlin/com/revolut/kompot/KompotPlugin.kt
+++ b/kompot/src/main/kotlin/com/revolut/kompot/KompotPlugin.kt
@@ -16,13 +16,27 @@
package com.revolut.kompot
+import com.revolut.kompot.lifecycle.ControllerLifecycleCallbacks
import com.revolut.kompot.navigable.Controller
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import java.util.concurrent.CopyOnWriteArrayList
object KompotPlugin {
+
internal val controllerShownSharedFlow = MutableSharedFlow(extraBufferCapacity = 16, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+ internal val controllerLifecycleCallbacks = CopyOnWriteArrayList()
+
+ @Deprecated("Use registerControllerLifecycleCallbacks with ControllerLifecycleCallbacks.onControllerAttached")
+ fun controllerShowingStream(): Flow = controllerShownSharedFlow.distinctUntilChanged()
+
+ fun registerControllerLifecycleCallbacks(callbacks: ControllerLifecycleCallbacks) {
+ controllerLifecycleCallbacks.add(callbacks)
+ }
- fun controllerShowingStream(): Flow = controllerShownSharedFlow
+ fun unregisterControllerLifecycleCallbacks(callbacks: ControllerLifecycleCallbacks) {
+ controllerLifecycleCallbacks.remove(callbacks)
+ }
}
\ No newline at end of file
diff --git a/kompot/src/main/kotlin/com/revolut/kompot/common/ControllerProvider.kt b/kompot/src/main/kotlin/com/revolut/kompot/common/ControllerProvider.kt
new file mode 100644
index 0000000..bd3f141
--- /dev/null
+++ b/kompot/src/main/kotlin/com/revolut/kompot/common/ControllerProvider.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 Revolut
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.revolut.kompot.common
+
+import com.revolut.kompot.navigable.vc.ViewController
+
+interface ControllerDescriptor {
+
+ fun resolve(viewController: ViewController): ControllerHolder = ControllerHolder(viewController)
+}
+
+data class ControllerRequest(val descriptor: ControllerDescriptor<*>) : Event()
+data class ControllerHolder internal constructor(val controller: ViewController<*>) : EventResult
\ No newline at end of file
diff --git a/kompot/src/main/kotlin/com/revolut/kompot/common/EmptyControllerContract.kt b/kompot/src/main/kotlin/com/revolut/kompot/common/EmptyControllerContract.kt
new file mode 100644
index 0000000..c757890
--- /dev/null
+++ b/kompot/src/main/kotlin/com/revolut/kompot/common/EmptyControllerContract.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 Revolut
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.revolut.kompot.common
+
+import com.revolut.kompot.navigable.screen.BaseScreenModel
+import com.revolut.kompot.navigable.screen.ScreenStates
+import com.revolut.kompot.navigable.screen.StateMapper
+
+class EmptyStateMapper : StateMapper {
+ override fun mapState(domainState: ScreenStates.EmptyDomain) = ScreenStates.EmptyUI
+}
+
+class EmptyListStateMapper : StateMapper {
+ override fun mapState(domainState: ScreenStates.EmptyDomain) = ScreenStates.EmptyUIList
+}
+
+class EmptyScreenModel