From 1013f032e025140e8c60aeeb8d0cb086725fd735 Mon Sep 17 00:00:00 2001 From: Laimonas Turauskas Date: Wed, 4 Sep 2024 11:54:24 -0400 Subject: [PATCH 1/2] Rename FragmentStoreBuilder to FeaturesBuilder. --- CHANGELOG.md | 3 +- .../formula/FragmentAndroidEventTest.kt | 3 +- .../formula/FragmentFlowRenderViewTest.kt | 3 +- .../formula/FragmentLifecycleStateTest.kt | 3 +- .../formula/FragmentLifecycleTest.kt | 3 +- .../formula/android/ActivityStore.kt | 4 +- .../formula/android/ActivityStoreContext.kt | 43 ++----------------- .../com/instacart/formula/android/Feature.kt | 2 +- .../formula/android/FeatureFactory.kt | 2 +- ...mentStoreBuilder.kt => FeaturesBuilder.kt} | 37 ++++++++-------- .../formula/android/FragmentFlowStore.kt | 18 ++++++-- .../android/internal/ActivityManager.kt | 6 +-- .../android/internal/FeatureBinding.kt | 4 +- .../formula/android/internal/Features.kt | 5 +++ .../android/ActivityStoreFactoryTest.kt | 2 +- .../formula/compose/stopwatch/StopwatchApp.kt | 3 +- .../main/java/com/examples/todoapp/TodoApp.kt | 3 +- 17 files changed, 65 insertions(+), 79 deletions(-) rename formula-android/src/main/java/com/instacart/formula/android/{FragmentStoreBuilder.kt => FeaturesBuilder.kt} (58%) create mode 100644 formula-android/src/main/java/com/instacart/formula/android/internal/Features.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 73461e4f0..9d22c9cc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ - Enable fine-grained control of dispatching via `Plugin.defaultDispatcher`, `RuntimeConfig.defaultDispatcher`, `Transition.ExecutionType` and `Effect.Type`. - Remove `RxStream` type alias. - Replace `implementation` function with a value -- Removed `FlowFactory` and `Flow` +- **Breaking**: Removed `FlowFactory` and `Flow` +- **Breaking**: Replace `FragmentStoreBuilder` with `FeaturesBuilder` ## [0.7.1] - June 28, 2022 - **Breaking**: Rename `FragmentBindingBuilder` to `FragmentStoreBuilder` diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt index 517aaa05d..2f487fa84 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt @@ -6,6 +6,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import com.instacart.formula.android.Feature import com.instacart.formula.android.FeatureFactory +import com.instacart.formula.android.FragmentFlowStore import com.instacart.formula.android.ViewFactory import com.instacart.formula.android.events.ActivityResult import com.instacart.formula.test.TestFragmentActivity @@ -29,7 +30,7 @@ class FragmentAndroidEventTest { configureActivity = { initialContract = TestLifecycleKey() }, - contracts = { + fragmentStore = FragmentFlowStore.init { val featureFactory = object : FeatureFactory { override fun initialize(dependencies: Unit, key: TestLifecycleKey): Feature { return Feature( diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt index 333c8a4b1..6520c38c7 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt @@ -10,6 +10,7 @@ import com.google.common.truth.Truth.assertThat import com.instacart.formula.android.FragmentFlowState import com.instacart.formula.android.FragmentKey import com.instacart.formula.android.BackCallback +import com.instacart.formula.android.FragmentFlowStore import com.instacart.formula.test.TestKey import com.instacart.formula.test.TestKeyWithId import com.instacart.formula.test.TestFragmentActivity @@ -49,7 +50,7 @@ class FragmentFlowRenderViewTest { updateThreads.add(Thread.currentThread()) }, - contracts = { + fragmentStore = FragmentFlowStore.init { bind(TestFeatureFactory { stateChanges(it) }) bind(TestFeatureFactory { stateChanges(it) }) } diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt index ac3401457..1125d2620 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt @@ -7,6 +7,7 @@ import com.google.common.truth.Truth.assertThat import com.instacart.formula.android.FormulaFragment import com.instacart.formula.android.ActivityStoreContext import com.instacart.formula.android.FeatureFactory +import com.instacart.formula.android.FragmentFlowStore import com.instacart.formula.android.FragmentKey import com.instacart.formula.test.TestKey import com.instacart.formula.test.TestKeyWithId @@ -36,7 +37,7 @@ class FragmentLifecycleStateTest { configureActivity = { initialContract = TestKey() }, - contracts = { + fragmentStore = FragmentFlowStore.init { bind(featureFactory(this@activity)) bind(featureFactory(this@activity)) } diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt index a08d461a1..7939fe90b 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt @@ -8,6 +8,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import com.instacart.formula.android.Feature import com.instacart.formula.android.FeatureFactory +import com.instacart.formula.android.FragmentFlowStore import com.instacart.formula.android.ViewFactory import com.instacart.formula.test.TestFragmentActivity import com.instacart.formula.test.TestFragmentLifecycleCallback @@ -36,7 +37,7 @@ class FragmentLifecycleTest { contract = TestLifecycleKey() initialContract = contract }, - contracts = { + fragmentStore = FragmentFlowStore.init { val featureFactory = object : FeatureFactory { override fun initialize(dependencies: Unit, key: TestLifecycleKey): Feature { return Feature( diff --git a/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt b/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt index 0e21c0347..ee44fb7e2 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt @@ -9,7 +9,7 @@ import io.reactivex.rxjava3.disposables.Disposable * navigation destination [com.instacart.formula.fragment.FragmentKey] to its state * management stream. * - * @param contracts Fragment state management defined for this [Activity]. + * @param fragmentStore Fragment state management defined for this [Activity]. * @param streams This provides ability to configure arbitrary RxJava streams that survive * configuration changes. Check [com.instacart.formula.android.StreamConfigurator] for utility methods. * @param configureActivity This is invoked as part of [com.instacart.formula.FormulaAndroid.onPreCreate]. You can @@ -18,7 +18,7 @@ import io.reactivex.rxjava3.disposables.Disposable * @param onFragmentLifecycleEvent This is callback for when a fragment is added or removed. */ class ActivityStore( - val contracts: FragmentFlowStore, + val fragmentStore: FragmentFlowStore, val streams: (StreamConfigurator.() -> Disposable)? = null, val configureActivity: ((Activity) -> Unit)? = null, val onRenderFragmentState: ((Activity, FragmentFlowState) -> Unit)? = null, diff --git a/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt b/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt index 70709c7f3..b3e5b66c5 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt @@ -79,58 +79,21 @@ abstract class ActivityStoreContext { * @param onFragmentLifecycleEvent This is called after each [FragmentLifecycleEvent]. * @param streams This provides ability to configure arbitrary RxJava streams that survive * configuration changes. Check [StreamConfigurator] for utility methods. - * @param contracts [FragmentFlowStore] used to provide state management for individual screens. + * @param fragmentStore [FragmentFlowStore] used to provide state management for individual screens. */ fun store( configureActivity: (ActivityT.() -> Unit)? = null, onRenderFragmentState: ((ActivityT, FragmentFlowState) -> Unit)? = null, onFragmentLifecycleEvent: ((FragmentLifecycleEvent) -> Unit)? = null, streams: (StreamConfigurator.() -> Disposable)? = null, - contracts: FragmentFlowStore + fragmentStore: FragmentFlowStore = FragmentFlowStore.EMPTY, ): ActivityStore { return ActivityStore( - contracts = contracts, + fragmentStore = fragmentStore, configureActivity = configureActivity, onFragmentLifecycleEvent = onFragmentLifecycleEvent, onRenderFragmentState = onRenderFragmentState, streams = streams ) } - - /** - * Creates an [ActivityStore]. - * - * @param configureActivity This is called when activity is created before view inflation. You can use this to - * configure / inject the activity. - * @param onRenderFragmentState This is called after [FragmentFlowState] is applied to UI. - * @param onFragmentLifecycleEvent This is called after each [FragmentLifecycleEvent]. - * @param streams This provides ability to configure arbitrary RxJava streams that survive - * configuration changes. Check [StreamConfigurator] for utility methods. - * @param contracts Builder method that configures [FragmentFlowStore] used to provide state management for individual screens. - */ - inline fun store( - noinline configureActivity: (ActivityT.() -> Unit)? = null, - noinline onRenderFragmentState: ((ActivityT, FragmentFlowState) -> Unit)? = null, - noinline onFragmentLifecycleEvent: ((FragmentLifecycleEvent) -> Unit)? = null, - noinline streams: (StreamConfigurator.() -> Disposable)? = null, - crossinline contracts: FragmentStoreBuilder.() -> Unit = {} - ): ActivityStore { - return store( - configureActivity = configureActivity, - onRenderFragmentState = onRenderFragmentState, - onFragmentLifecycleEvent = onFragmentLifecycleEvent, - streams = streams, - contracts = contracts(Unit, contracts) - ) - } - - /** - * Convenience method to to create a [FragmentFlowStore] with a [Component] instance. - */ - inline fun contracts( - rootComponent: Component, - crossinline contracts: FragmentStoreBuilder.() -> Unit - ): FragmentFlowStore { - return FragmentFlowStore.init(rootComponent, contracts) - } } diff --git a/formula-android/src/main/java/com/instacart/formula/android/Feature.kt b/formula-android/src/main/java/com/instacart/formula/android/Feature.kt index 5d472ad3e..d1e29ba56 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/Feature.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/Feature.kt @@ -8,7 +8,7 @@ import io.reactivex.rxjava3.core.Observable * and the [stateObservable] observable. * * To define a feature, we need to create a [FeatureFactory] for a specific [FragmentKey] type - * and [bind][FragmentStoreBuilder.bind] it to the [FragmentFlowStore]. + * and [bind][FeaturesBuilder.bind] it to the [FragmentFlowStore]. * * Take a look at [FeatureFactory] for more information. */ diff --git a/formula-android/src/main/java/com/instacart/formula/android/FeatureFactory.kt b/formula-android/src/main/java/com/instacart/formula/android/FeatureFactory.kt index d81a4fcce..8219ad51c 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/FeatureFactory.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/FeatureFactory.kt @@ -26,7 +26,7 @@ package com.instacart.formula.android * } * ``` * - * Once we define a [FeatureFactory], we need to [bind][FragmentStoreBuilder.bind] it to a + * Once we define a [FeatureFactory], we need to [bind][FeaturesBuilder.bind] it to a * [FragmentFlowStore]. The fragment flow store will call [initialize] the first time * [FormulaFragment] with a new [Key] is attached. It will subscribe to the state management * and persist it across configuration changes. diff --git a/formula-android/src/main/java/com/instacart/formula/android/FragmentStoreBuilder.kt b/formula-android/src/main/java/com/instacart/formula/android/FeaturesBuilder.kt similarity index 58% rename from formula-android/src/main/java/com/instacart/formula/android/FragmentStoreBuilder.kt rename to formula-android/src/main/java/com/instacart/formula/android/FeaturesBuilder.kt index f3e906233..a5765af92 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/FragmentStoreBuilder.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/FeaturesBuilder.kt @@ -1,26 +1,27 @@ package com.instacart.formula.android import com.instacart.formula.android.internal.FeatureBinding +import com.instacart.formula.android.internal.Features import com.instacart.formula.android.internal.MappedFeatureFactory import java.lang.IllegalStateException import kotlin.reflect.KClass /** - * A class used by [FragmentFlowStore] to register [fragment keys][FragmentKey] and their - * feature factories. + * Helps to build a [Features] list that binds various fragment keys to their respective + * feature factories. Each feature factory has a dependency type that needs to either match + * [Dependencies] type defined here or map this root dependency type to the custom type. */ -class FragmentStoreBuilder { +class FeaturesBuilder { companion object { - @PublishedApi - internal inline fun build( - init: FragmentStoreBuilder.() -> Unit - ): List> { - return FragmentStoreBuilder().apply(init).build() + inline fun build( + init: FeaturesBuilder.() -> Unit + ): Features { + return FeaturesBuilder().apply(init).build() } } private val types = mutableSetOf>() - private val bindings: MutableList> = mutableListOf() + private val bindings: MutableList> = mutableListOf() /** * Binds a [feature factory][FeatureFactory] for a specific [key][type]. @@ -30,7 +31,7 @@ class FragmentStoreBuilder { */ fun bind( type : KClass, - featureFactory: FeatureFactory, + featureFactory: FeatureFactory, ) = apply { val binding = FeatureBinding(type.java, featureFactory) bind(type.java, binding) @@ -42,7 +43,7 @@ class FragmentStoreBuilder { * @param featureFactory Feature factory that provides state observable and view rendering logic. */ inline fun bind( - featureFactory: FeatureFactory + featureFactory: FeatureFactory ) = apply { bind(Key::class, featureFactory) } @@ -51,11 +52,11 @@ class FragmentStoreBuilder { * A convenience inline function that binds a feature factory for a specific [key][Key]. * * @param featureFactory Feature factory that provides state observable and view rendering logic. - * @param toDependencies Maps [Component] to feature factory [dependencies][Dependencies]. + * @param toDependencies Maps [Dependencies] to feature factory [dependencies][CustomDependencyType]. */ - inline fun bind( - featureFactory: FeatureFactory, - noinline toDependencies: (Component) -> Dependencies + inline fun bind( + featureFactory: FeatureFactory, + noinline toDependencies: (Dependencies) -> CustomDependencyType ) = apply { val mapped = MappedFeatureFactory( delegate = featureFactory, @@ -65,11 +66,11 @@ class FragmentStoreBuilder { } @PublishedApi - internal fun build(): List> { - return bindings + internal fun build(): Features { + return Features(bindings) } - private fun bind(type: Class<*>, binding: FeatureBinding) = apply { + private fun bind(type: Class<*>, binding: FeatureBinding) = apply { if (types.contains(type)) { throw IllegalStateException("Binding for $type already exists") } diff --git a/formula-android/src/main/java/com/instacart/formula/android/FragmentFlowStore.kt b/formula-android/src/main/java/com/instacart/formula/android/FragmentFlowStore.kt index 7302e0437..e0255bdca 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/FragmentFlowStore.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/FragmentFlowStore.kt @@ -2,6 +2,7 @@ package com.instacart.formula.android import com.instacart.formula.RuntimeConfig import com.instacart.formula.android.events.FragmentLifecycleEvent +import com.instacart.formula.android.internal.Features import com.instacart.formula.android.internal.FragmentFlowStoreFormula import com.instacart.formula.android.utils.MainThreadDispatcher import com.instacart.formula.rxjava3.toObservable @@ -14,18 +15,27 @@ class FragmentFlowStore @PublishedApi internal constructor( private val formula: FragmentFlowStoreFormula<*>, ) { companion object { + val EMPTY = init { } + inline fun init( - crossinline init: FragmentStoreBuilder.() -> Unit + crossinline init: FeaturesBuilder.() -> Unit ): FragmentFlowStore { return init(Unit, init) } inline fun init( rootComponent: Component, - crossinline contracts: FragmentStoreBuilder.() -> Unit + crossinline init: FeaturesBuilder.() -> Unit + ): FragmentFlowStore { + val features = FeaturesBuilder.build(init) + return init(rootComponent, features) + } + + fun init( + component: Component, + features: Features ): FragmentFlowStore { - val bindings = FragmentStoreBuilder.build(contracts) - val formula = FragmentFlowStoreFormula(rootComponent, bindings) + val formula = FragmentFlowStoreFormula(component, features.bindings) return FragmentFlowStore(formula) } } diff --git a/formula-android/src/main/java/com/instacart/formula/android/internal/ActivityManager.kt b/formula-android/src/main/java/com/instacart/formula/android/internal/ActivityManager.kt index 9089aeb24..51bdc818a 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/internal/ActivityManager.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/internal/ActivityManager.kt @@ -43,11 +43,11 @@ internal class ActivityManager( activity = activity, fragmentEnvironment = environment, onLifecycleEvent = { - store.contracts.onLifecycleEffect(it) + store.fragmentStore.onLifecycleEffect(it) store.onFragmentLifecycleEvent?.invoke(it) }, onLifecycleState = delegate::updateFragmentLifecycleState, - onFragmentViewStateChanged = store.contracts::onVisibilityChanged + onFragmentViewStateChanged = store.fragmentStore::onVisibilityChanged ) } @@ -108,7 +108,7 @@ internal class ActivityManager( private fun subscribeToFragmentStateChanges(): Disposable { return store - .contracts + .fragmentStore .state(environment) .subscribe(delegate.fragmentFlowStateRelay::accept) } diff --git a/formula-android/src/main/java/com/instacart/formula/android/internal/FeatureBinding.kt b/formula-android/src/main/java/com/instacart/formula/android/internal/FeatureBinding.kt index fd4e7732e..2e88540e9 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/internal/FeatureBinding.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/internal/FeatureBinding.kt @@ -6,7 +6,7 @@ import com.instacart.formula.android.FragmentKey /** * Defines how a specific key should be bound to its [FeatureFactory] */ -class FeatureBinding( +class FeatureBinding( val type: Class, - val feature: FeatureFactory, + val feature: FeatureFactory, ) diff --git a/formula-android/src/main/java/com/instacart/formula/android/internal/Features.kt b/formula-android/src/main/java/com/instacart/formula/android/internal/Features.kt new file mode 100644 index 000000000..4cedf8d3c --- /dev/null +++ b/formula-android/src/main/java/com/instacart/formula/android/internal/Features.kt @@ -0,0 +1,5 @@ +package com.instacart.formula.android.internal + +class Features( + val bindings: List>, +) diff --git a/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt b/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt index 62e7c26b7..df7b7f086 100644 --- a/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt +++ b/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt @@ -18,7 +18,7 @@ class ActivityStoreFactoryTest { environment = FragmentEnvironment(), activities = { activity(FakeActivity::class) { - store { } + store() } } ) diff --git a/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt b/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt index 67f744391..c263decbe 100644 --- a/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt +++ b/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt @@ -4,6 +4,7 @@ import android.app.Application import android.util.Log import com.instacart.formula.FormulaAndroid import com.instacart.formula.android.FragmentEnvironment +import com.instacart.formula.android.FragmentFlowStore class StopwatchApp : Application() { @@ -20,7 +21,7 @@ class StopwatchApp : Application() { activities = { activity { store( - contracts = contracts(Unit) { + fragmentStore = FragmentFlowStore.init(Unit) { bind(StopwatchFeatureFactory()) } ) diff --git a/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt b/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt index 8429b16e3..ae4a785f9 100644 --- a/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt +++ b/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt @@ -5,6 +5,7 @@ import android.util.Log import com.examples.todoapp.tasks.TaskListFeatureFactory import com.instacart.formula.FormulaAndroid import com.instacart.formula.android.FragmentEnvironment +import com.instacart.formula.android.FragmentFlowStore class TodoApp : Application() { @@ -23,7 +24,7 @@ class TodoApp : Application() { val component = TodoAppComponent(this) store( - contracts = contracts(component) { + fragmentStore = FragmentFlowStore.init(component) { bind(TaskListFeatureFactory()) } ) From ecf62dd717487ab2643f693a0c56de7f0b512678 Mon Sep 17 00:00:00 2001 From: Laimonas Turauskas Date: Wed, 4 Sep 2024 13:48:27 -0400 Subject: [PATCH 2/2] Construct ActivityStore directly. --- docs/Formula-Android.md | 20 ++++++++----- docs/index.md | 2 +- .../formula/ActivityLifecycleEventTest.kt | 3 +- .../instacart/formula/ActivityUpdateTest.kt | 3 +- .../formula/ActivityUpdateTimingTest.kt | 3 +- .../formula/FragmentAndroidEventTest.kt | 5 ++-- .../formula/FragmentFlowRenderViewTest.kt | 9 +++--- .../formula/FragmentLifecycleStateTest.kt | 5 ++-- .../formula/FragmentLifecycleTest.kt | 7 +++-- .../formula/android/ActivityStore.kt | 2 +- .../formula/android/ActivityStoreContext.kt | 29 ------------------- .../android/ActivityStoreFactoryTest.kt | 2 +- .../formula/compose/stopwatch/StopwatchApp.kt | 3 +- .../main/java/com/examples/todoapp/TodoApp.kt | 3 +- 14 files changed, 40 insertions(+), 56 deletions(-) diff --git a/docs/Formula-Android.md b/docs/Formula-Android.md index 7c28720ed..09571554a 100644 --- a/docs/Formula-Android.md +++ b/docs/Formula-Android.md @@ -215,9 +215,11 @@ class MyApp : Application() { FormulaAndroid.init(this) { activity(MyActivity::class) { - store(MyActivityComponent(this)) { - bind(CounterFeatureFactory()) - } + ActivityStore( + fragmentStore = FragmentFlowStore.init(MyActivityComponent(this)) { + bind(CounterFeatureFactory()) + } + ) } } } @@ -357,9 +359,11 @@ Now that we have our dependencies configured, let's bind the flow factory to our val appComponent = AppComponent() FormulaAndroid.init(this) { activity(MyActivity::class) { - store(appComponent) { - bind(AuthFlowFactory()) - } + ActivityStore( + fragmentStore = FragmentFlowStore.init(appComponent) { + bind(AuthFlowFactory()) + } + ) } } ``` @@ -393,7 +397,7 @@ class MyApp : Application() { FormulaAndroid.init(this) { activity { - store( + ActivityStore( streams = { // You can subscribe to your RxJava streams here. val timerState = Observable @@ -453,7 +457,7 @@ FormulaAndroid.init(this) { // This component will survive configuration changes. val activityComponent = appComponent.createMyActivityComponent() - store( + ActivityStore( configureActivity = { // in this callback `this` is the instance of MyActivity // so we can use it to inject dependencies diff --git a/docs/index.md b/docs/index.md index cc8315372..10ddd5ea5 100755 --- a/docs/index.md +++ b/docs/index.md @@ -169,7 +169,7 @@ class MyApp : Application() { FormulaAndroid.init(this) { activity { - store( + ActivityStore( streams = { val formula = CounterFormula() update(formula.toObservable(), MyActivity::render) diff --git a/formula-android-tests/src/test/java/com/instacart/formula/ActivityLifecycleEventTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/ActivityLifecycleEventTest.kt index 19dd4929a..2b097bd86 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/ActivityLifecycleEventTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/ActivityLifecycleEventTest.kt @@ -6,6 +6,7 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FormulaAppCompatActivity import org.junit.Before import org.junit.Rule @@ -25,7 +26,7 @@ class ActivityLifecycleEventTest { FormulaAndroid.init(app) { activity { events = mutableListOf() - store( + ActivityStore( streams = { activityLifecycleState().subscribe { events.add(it) diff --git a/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTest.kt index 2758fbd58..349d296a4 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTest.kt @@ -5,6 +5,7 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FormulaAppCompatActivity import com.jakewharton.rxrelay3.PublishRelay import org.junit.Before @@ -35,7 +36,7 @@ class ActivityUpdateTest { initFormula = { app -> FormulaAndroid.init(app) { activity { - store( + ActivityStore( streams = { update(updateRelay, TestActivity::applyUpdate) } diff --git a/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTimingTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTimingTest.kt index abfd6e663..1b3b2b5b1 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTimingTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/ActivityUpdateTimingTest.kt @@ -5,6 +5,7 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FormulaAppCompatActivity import io.reactivex.rxjava3.core.Observable import org.junit.Before @@ -38,7 +39,7 @@ class ActivityUpdateTimingTest { initFormula = { app -> FormulaAndroid.init(app) { activity { - store( + ActivityStore( streams = { update(updateRelay, TestActivity::applyUpdate) } diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt index 2f487fa84..771f94825 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentAndroidEventTest.kt @@ -4,6 +4,7 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.Feature import com.instacart.formula.android.FeatureFactory import com.instacart.formula.android.FragmentFlowStore @@ -26,9 +27,9 @@ class FragmentAndroidEventTest { initFormula = { app -> FormulaAndroid.init(app) { activity { - store( + ActivityStore( configureActivity = { - initialContract = TestLifecycleKey() + it.initialContract = TestLifecycleKey() }, fragmentStore = FragmentFlowStore.init { val featureFactory = object : FeatureFactory { diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt index 6520c38c7..85912ff0f 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt @@ -7,6 +7,7 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FragmentFlowState import com.instacart.formula.android.FragmentKey import com.instacart.formula.android.BackCallback @@ -40,10 +41,10 @@ class FragmentFlowRenderViewTest { initFormula = { app -> FormulaAndroid.init(app) { activity { - store( - configureActivity = { - initialContract = TestKey() - onPreCreated(this) + ActivityStore( + configureActivity = { activity -> + activity.initialContract = TestKey() + onPreCreated(activity) }, onRenderFragmentState = { a, state -> lastState = state diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt index 1125d2620..1aeeab506 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleStateTest.kt @@ -4,6 +4,7 @@ import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FormulaFragment import com.instacart.formula.android.ActivityStoreContext import com.instacart.formula.android.FeatureFactory @@ -33,9 +34,9 @@ class FragmentLifecycleStateTest { started = mutableListOf() resumed = mutableListOf() - store( + ActivityStore( configureActivity = { - initialContract = TestKey() + it.initialContract = TestKey() }, fragmentStore = FragmentFlowStore.init { bind(featureFactory(this@activity)) diff --git a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt index 7939fe90b..fedb82b5e 100644 --- a/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt +++ b/formula-android-tests/src/test/java/com/instacart/formula/FragmentLifecycleTest.kt @@ -6,6 +6,7 @@ import android.os.Bundle import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.Feature import com.instacart.formula.android.FeatureFactory import com.instacart.formula.android.FragmentFlowStore @@ -31,11 +32,11 @@ class FragmentLifecycleTest { @get:Rule val formulaRule = TestFormulaRule(initFormula = { app -> FormulaAndroid.init(app) { activity { - store( - configureActivity = { + ActivityStore( + configureActivity = { activity -> lifecycleCallback = TestFragmentLifecycleCallback() contract = TestLifecycleKey() - initialContract = contract + activity.initialContract = contract }, fragmentStore = FragmentFlowStore.init { val featureFactory = object : FeatureFactory { diff --git a/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt b/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt index ee44fb7e2..0bc9f0cd6 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/ActivityStore.kt @@ -18,7 +18,7 @@ import io.reactivex.rxjava3.disposables.Disposable * @param onFragmentLifecycleEvent This is callback for when a fragment is added or removed. */ class ActivityStore( - val fragmentStore: FragmentFlowStore, + val fragmentStore: FragmentFlowStore = FragmentFlowStore.EMPTY, val streams: (StreamConfigurator.() -> Disposable)? = null, val configureActivity: ((Activity) -> Unit)? = null, val onRenderFragmentState: ((Activity, FragmentFlowState) -> Unit)? = null, diff --git a/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt b/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt index b3e5b66c5..a575c5ae5 100644 --- a/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt +++ b/formula-android/src/main/java/com/instacart/formula/android/ActivityStoreContext.kt @@ -3,9 +3,7 @@ package com.instacart.formula.android import androidx.fragment.app.FragmentActivity import androidx.lifecycle.Lifecycle import com.instacart.formula.android.events.ActivityResult -import com.instacart.formula.android.events.FragmentLifecycleEvent import io.reactivex.rxjava3.core.Observable -import io.reactivex.rxjava3.disposables.Disposable /** * This class provides context within which you can create [ActivityStore]. It provides @@ -69,31 +67,4 @@ abstract class ActivityStoreContext { * it will do nothing. */ abstract fun send(effect: Activity.() -> Unit) - - /** - * Creates an [ActivityStore]. - * - * @param configureActivity This is called when activity is created before view inflation. You can use this to - * configure / inject the activity. - * @param onRenderFragmentState This is called after [FragmentFlowState] is applied to UI. - * @param onFragmentLifecycleEvent This is called after each [FragmentLifecycleEvent]. - * @param streams This provides ability to configure arbitrary RxJava streams that survive - * configuration changes. Check [StreamConfigurator] for utility methods. - * @param fragmentStore [FragmentFlowStore] used to provide state management for individual screens. - */ - fun store( - configureActivity: (ActivityT.() -> Unit)? = null, - onRenderFragmentState: ((ActivityT, FragmentFlowState) -> Unit)? = null, - onFragmentLifecycleEvent: ((FragmentLifecycleEvent) -> Unit)? = null, - streams: (StreamConfigurator.() -> Disposable)? = null, - fragmentStore: FragmentFlowStore = FragmentFlowStore.EMPTY, - ): ActivityStore { - return ActivityStore( - fragmentStore = fragmentStore, - configureActivity = configureActivity, - onFragmentLifecycleEvent = onFragmentLifecycleEvent, - onRenderFragmentState = onRenderFragmentState, - streams = streams - ) - } } diff --git a/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt b/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt index df7b7f086..13414be72 100644 --- a/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt +++ b/formula-android/src/test/java/com/instacart/formula/android/ActivityStoreFactoryTest.kt @@ -18,7 +18,7 @@ class ActivityStoreFactoryTest { environment = FragmentEnvironment(), activities = { activity(FakeActivity::class) { - store() + ActivityStore() } } ) diff --git a/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt b/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt index c263decbe..21e2fdc49 100644 --- a/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt +++ b/samples/stopwatch-compose/src/main/java/com/instacart/formula/compose/stopwatch/StopwatchApp.kt @@ -3,6 +3,7 @@ package com.instacart.formula.compose.stopwatch import android.app.Application import android.util.Log import com.instacart.formula.FormulaAndroid +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FragmentEnvironment import com.instacart.formula.android.FragmentFlowStore @@ -20,7 +21,7 @@ class StopwatchApp : Application() { ), activities = { activity { - store( + ActivityStore( fragmentStore = FragmentFlowStore.init(Unit) { bind(StopwatchFeatureFactory()) } diff --git a/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt b/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt index ae4a785f9..b6e983f63 100644 --- a/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt +++ b/samples/todoapp/src/main/java/com/examples/todoapp/TodoApp.kt @@ -4,6 +4,7 @@ import android.app.Application import android.util.Log import com.examples.todoapp.tasks.TaskListFeatureFactory import com.instacart.formula.FormulaAndroid +import com.instacart.formula.android.ActivityStore import com.instacart.formula.android.FragmentEnvironment import com.instacart.formula.android.FragmentFlowStore @@ -23,7 +24,7 @@ class TodoApp : Application() { activity { val component = TodoAppComponent(this) - store( + ActivityStore( fragmentStore = FragmentFlowStore.init(component) { bind(TaskListFeatureFactory()) }