Skip to content

Commit

Permalink
Rename FragmentFlowStore to FragmentStore and update related classes. (
Browse files Browse the repository at this point in the history
  • Loading branch information
Laimiux authored Sep 4, 2024
1 parent fc65f7f commit 857d6b4
Show file tree
Hide file tree
Showing 22 changed files with 89 additions and 91 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Replace `implementation` function with a value
- **Breaking**: Removed `FlowFactory` and `Flow`
- **Breaking**: Replace `FragmentStoreBuilder` with `FeaturesBuilder`
- **Breaking**: Rename `FragmentFlowStore` to `FragmentStore`, `FragmentState` to `FragmentOutput`, `FragmentFlowState` to `FragmentState`

## [0.7.1] - June 28, 2022
- **Breaking**: Rename `FragmentBindingBuilder` to `FragmentStoreBuilder`
Expand Down
4 changes: 2 additions & 2 deletions docs/Formula-Android.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class MyApp : Application() {
FormulaAndroid.init(this) {
activity(MyActivity::class) {
ActivityStore(
fragmentStore = FragmentFlowStore.init(MyActivityComponent(this)) {
fragmentStore = FragmentStore.init(MyActivityComponent(this)) {
bind(CounterFeatureFactory())
}
)
Expand Down Expand Up @@ -360,7 +360,7 @@ val appComponent = AppComponent()
FormulaAndroid.init(this) {
activity(MyActivity::class) {
ActivityStore(
fragmentStore = FragmentFlowStore.init(appComponent) {
fragmentStore = FragmentStore.init(appComponent) {
bind(AuthFlowFactory())
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ 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
import com.instacart.formula.android.FragmentStore
import com.instacart.formula.android.ViewFactory
import com.instacart.formula.android.events.ActivityResult
import com.instacart.formula.test.TestFragmentActivity
Expand All @@ -31,7 +31,7 @@ class FragmentAndroidEventTest {
configureActivity = {
it.initialContract = TestLifecycleKey()
},
fragmentStore = FragmentFlowStore.init {
fragmentStore = FragmentStore.init {
val featureFactory = object : FeatureFactory<Unit, TestLifecycleKey> {
override fun initialize(dependencies: Unit, key: TestLifecycleKey): Feature {
return Feature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ 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.FragmentState
import com.instacart.formula.android.FragmentKey
import com.instacart.formula.android.BackCallback
import com.instacart.formula.android.FragmentFlowStore
import com.instacart.formula.android.FragmentStore
import com.instacart.formula.test.TestKey
import com.instacart.formula.test.TestKeyWithId
import com.instacart.formula.test.TestFragmentActivity
Expand All @@ -33,7 +33,7 @@ class FragmentFlowRenderViewTest {

class HeadlessFragment : Fragment()

private var lastState: FragmentFlowState? = null
private var lastState: FragmentState? = null
private val stateChangeRelay = PublishRelay.create<Pair<FragmentKey, Any>>()
private var onPreCreated: (TestFragmentActivity) -> Unit = {}
private var updateThreads = linkedSetOf<Thread>()
Expand All @@ -51,7 +51,7 @@ class FragmentFlowRenderViewTest {

updateThreads.add(Thread.currentThread())
},
fragmentStore = FragmentFlowStore.init {
fragmentStore = FragmentStore.init {
bind(TestFeatureFactory<TestKey> { stateChanges(it) })
bind(TestFeatureFactory<TestKeyWithId> { stateChanges(it) })
}
Expand Down Expand Up @@ -241,7 +241,7 @@ class FragmentFlowRenderViewTest {

Shadows.shadowOf(Looper.getMainLooper()).idle()

val currentState = lastState?.states.orEmpty()
val currentState = lastState?.outputs.orEmpty()
.mapKeys { it.key.key }
.mapValues { it.value.renderModel }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.instacart.formula.android.ActivityStore
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.FragmentStore
import com.instacart.formula.android.FragmentKey
import com.instacart.formula.test.TestKey
import com.instacart.formula.test.TestKeyWithId
Expand Down Expand Up @@ -38,7 +38,7 @@ class FragmentLifecycleStateTest {
configureActivity = {
it.initialContract = TestKey()
},
fragmentStore = FragmentFlowStore.init {
fragmentStore = FragmentStore.init {
bind(featureFactory<TestKey>(this@activity))
bind(featureFactory<TestKeyWithId>(this@activity))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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
import com.instacart.formula.android.FragmentStore
import com.instacart.formula.android.ViewFactory
import com.instacart.formula.test.TestFragmentActivity
import com.instacart.formula.test.TestFragmentLifecycleCallback
Expand Down Expand Up @@ -38,7 +38,7 @@ class FragmentLifecycleTest {
contract = TestLifecycleKey()
activity.initialContract = contract
},
fragmentStore = FragmentFlowStore.init {
fragmentStore = FragmentStore.init {
val featureFactory = object : FeatureFactory<Unit, TestLifecycleKey> {
override fun initialize(dependencies: Unit, key: TestLifecycleKey): Feature {
return Feature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import io.reactivex.rxjava3.disposables.Disposable
* 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
* use this callback to inject the activity.
* @param onRenderFragmentState This is invoked after [FragmentFlowState] has been updated.
* @param onRenderFragmentState This is invoked after [FragmentState] has been updated.
* @param onFragmentLifecycleEvent This is callback for when a fragment is added or removed.
*/
class ActivityStore<Activity : FragmentActivity>(
val fragmentStore: FragmentFlowStore = FragmentFlowStore.EMPTY,
val fragmentStore: FragmentStore = FragmentStore.EMPTY,
val streams: (StreamConfigurator<Activity>.() -> Disposable)? = null,
val configureActivity: ((Activity) -> Unit)? = null,
val onRenderFragmentState: ((Activity, FragmentFlowState) -> Unit)? = null,
val onRenderFragmentState: ((Activity, FragmentState) -> Unit)? = null,
val onFragmentLifecycleEvent: ((FragmentLifecycleEvent) -> Unit)? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ abstract class ActivityStoreContext<out Activity : FragmentActivity> {
abstract fun activityLifecycleState(): Observable<Lifecycle.State>

/**
* Returns RxJava stream that emits [FragmentFlowStore] state changes.
* Returns RxJava stream that emits [FragmentStore] state changes.
*/
abstract fun fragmentFlowState(): Observable<FragmentFlowState>
abstract fun fragmentState(): Observable<FragmentState>

/**
* Returns RxJava stream that emits true if fragment with a specific [tag] has
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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][FeaturesBuilder.bind] it to the [FragmentFlowStore].
* and [bind][FeaturesBuilder.bind] it to the [FragmentStore].
*
* Take a look at [FeatureFactory] for more information.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ package com.instacart.formula.android
* ```
*
* 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
* [FragmentStore]. 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.
*
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.instacart.formula.android

/**
* Defines the current render model for a specific [key].
*/
data class FragmentOutput(val key: FragmentKey, val renderModel: Any)
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
package com.instacart.formula.android

/**
* Defines the current render model for a specific [key].
* Represents currently [activeIds] and their [outputs].
*
* @param activeIds Fragment contracts that are running their state management.
* @param visibleIds Fragment contracts that are currently visible to the user.
* @param outputs Last emitted output of each active [FragmentKey].
*/
data class FragmentState(val key: FragmentKey, val renderModel: Any)
data class FragmentState(
val activeIds: List<FragmentId> = emptyList(),
val visibleIds: List<FragmentId> = emptyList(),
val features: Map<FragmentId, FeatureEvent> = emptyMap(),
val outputs: Map<FragmentId, FragmentOutput> = emptyMap()
) {
fun visibleOutput() = visibleIds.lastOrNull()?.let { outputs[it] }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,40 @@ 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.internal.FragmentStoreFormula
import com.instacart.formula.android.utils.MainThreadDispatcher
import com.instacart.formula.rxjava3.toObservable
import io.reactivex.rxjava3.core.Observable

/**
* A FragmentFlowStore is responsible for managing the state of multiple [FragmentKey] instances.
* A FragmentStore is responsible for managing the state of multiple [FragmentKey] instances.
*/
class FragmentFlowStore @PublishedApi internal constructor(
private val formula: FragmentFlowStoreFormula<*>,
class FragmentStore @PublishedApi internal constructor(
private val formula: FragmentStoreFormula<*>,
) {
companion object {
val EMPTY = init { }

inline fun init(
crossinline init: FeaturesBuilder<Unit>.() -> Unit
): FragmentFlowStore {
): FragmentStore {
return init(Unit, init)
}

inline fun <Component> init(
rootComponent: Component,
crossinline init: FeaturesBuilder<Component>.() -> Unit
): FragmentFlowStore {
): FragmentStore {
val features = FeaturesBuilder.build(init)
return init(rootComponent, features)
}

fun <Component> init(
component: Component,
features: Features<Component>
): FragmentFlowStore {
val formula = FragmentFlowStoreFormula(component, features.bindings)
return FragmentFlowStore(formula)
): FragmentStore {
val formula = FragmentStoreFormula(component, features.bindings)
return FragmentStore(formula)
}
}

Expand All @@ -48,7 +48,7 @@ class FragmentFlowStore @PublishedApi internal constructor(
formula.onVisibilityChanged(contract, visible)
}

internal fun state(environment: FragmentEnvironment): Observable<FragmentFlowState> {
internal fun state(environment: FragmentEnvironment): Observable<FragmentState> {
val config = RuntimeConfig(
defaultDispatcher = MainThreadDispatcher(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ internal class ActivityManager<Activity : FragmentActivity>(
delegate.onLifecycleStateChanged(Lifecycle.State.CREATED)
val renderView = fragmentRenderView ?: throw callOnPreCreateException(activity)

uiSubscription = delegate.fragmentFlowState().subscribe {
uiSubscription = delegate.fragmentState().subscribe {
renderView.render(it)
store.onRenderFragmentState?.invoke(activity, it)
}
Expand Down Expand Up @@ -110,7 +110,7 @@ internal class ActivityManager<Activity : FragmentActivity>(
return store
.fragmentStore
.state(environment)
.subscribe(delegate.fragmentFlowStateRelay::accept)
.subscribe(delegate.fragmentStateRelay::accept)
}

private fun callOnPreCreateException(activity: FragmentActivity): IllegalStateException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.instacart.formula.android.internal
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import com.instacart.formula.android.events.ActivityResult
import com.instacart.formula.android.FragmentFlowState
import com.instacart.formula.android.FragmentState
import com.instacart.formula.android.FragmentKey
import com.instacart.formula.android.FragmentId
import com.instacart.formula.android.ActivityStoreContext
Expand All @@ -27,13 +27,13 @@ internal class ActivityStoreContextImpl<Activity : FragmentActivity> : ActivityS

private val lifecycleStates = BehaviorRelay.createDefault<Lifecycle.State>(Lifecycle.State.INITIALIZED)
private val activityResultRelay: PublishRelay<ActivityResult> = PublishRelay.create()
internal val fragmentFlowStateRelay: BehaviorRelay<FragmentFlowState> = BehaviorRelay.create()
internal val fragmentStateRelay: BehaviorRelay<FragmentState> = BehaviorRelay.create()

override fun activityLifecycleState(): Observable<Lifecycle.State> = lifecycleStates

override fun activityResults(): Observable<ActivityResult> = activityResultRelay

override fun fragmentFlowState(): Observable<FragmentFlowState> = fragmentFlowStateRelay
override fun fragmentState(): Observable<FragmentState> = fragmentStateRelay

override fun isFragmentStarted(tag: String): Observable<Boolean> {
return fragmentLifecycleState(tag)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal class FormulaFragmentViewFactory(
val featureEvent = featureProvider.getFeature(fragmentId) ?: throw IllegalStateException("Could not find feature for $key.")
val viewFactory = factory ?: when (featureEvent) {
is FeatureEvent.MissingBinding -> {
throw IllegalStateException("Missing feature factory or integration for $key. Please check your FragmentFlowStore configuration.")
throw IllegalStateException("Missing feature factory or integration for $key. Please check your FragmentStore configuration.")
}
is FeatureEvent.Failure -> {
throw IllegalStateException("Feature failed to initialize: $key", featureEvent.error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,24 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import com.instacart.formula.Renderer
import com.instacart.formula.RenderView
import com.instacart.formula.android.BaseFormulaFragment
import com.instacart.formula.android.FormulaFragment
import com.instacart.formula.android.FragmentEnvironment
import com.instacart.formula.android.FragmentFlowState
import com.instacart.formula.android.FragmentState
import com.instacart.formula.android.events.FragmentLifecycleEvent
import com.instacart.formula.android.BackCallback
import com.instacart.formula.android.FeatureEvent
import com.instacart.formula.android.FragmentId
import com.instacart.formula.android.ViewFactory
import java.util.LinkedList
import java.util.UUID

/**
* Renders [FragmentFlowState] and provides back button handling.
* Renders [FragmentState] and provides back button handling.
*
* NOTE: Initialize this class before calling [FragmentActivity.super.onCreate]
*
* [activity] activity within which the [FragmentFlowRenderView] lives.
* [onLifecycleEvent] fragment lifecycle events that should be passed to the [com.instacart.formula.fragment.FragmentFlowStore]
* [onLifecycleEvent] fragment lifecycle events that should be passed to the [com.instacart.formula.android.FragmentStore]
*/
internal class FragmentFlowRenderView(
private val activity: FragmentActivity,
Expand All @@ -37,7 +34,7 @@ internal class FragmentFlowRenderView(
private val onFragmentViewStateChanged: (FragmentId, isVisible: Boolean) -> Unit
) {

private var fragmentState: FragmentFlowState? = null
private var fragmentState: FragmentState? = null
private val visibleFragments: LinkedList<Fragment> = LinkedList()

private val featureProvider = object : FeatureProvider {
Expand Down Expand Up @@ -117,7 +114,7 @@ internal class FragmentFlowRenderView(
activity.supportFragmentManager.registerFragmentLifecycleCallbacks(callback, false)
}

fun render(state: FragmentFlowState) {
fun render(state: FragmentState) {
Utils.assertMainThread()

fragmentState = state
Expand All @@ -127,7 +124,7 @@ internal class FragmentFlowRenderView(
fun onBackPressed(): Boolean {
val lastFragment = visibleFragments.lastOrNull()
if (lastFragment is BaseFormulaFragment<*>) {
val state = fragmentState?.states?.get(lastFragment.getFormulaFragmentId())?.renderModel
val state = fragmentState?.outputs?.get(lastFragment.getFormulaFragmentId())?.renderModel
return state is BackCallback && state.onBackPressed()
}
return false
Expand All @@ -152,10 +149,10 @@ internal class FragmentFlowRenderView(
onLifecycleState.invoke(fragment.getFormulaFragmentId(), newState)
}

private fun updateVisibleFragments(state: FragmentFlowState) {
private fun updateVisibleFragments(state: FragmentState) {
visibleFragments.forEachIndices { fragment ->
if (fragment is BaseFormulaFragment<*>) {
state.states[fragment.getFormulaFragmentId()]?.let {
state.outputs[fragment.getFormulaFragmentId()]?.let {
(fragment as BaseFormulaFragment<Any>).setState(it.renderModel)
}
}
Expand Down
Loading

0 comments on commit 857d6b4

Please sign in to comment.