-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
151 additions
and
177 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
formula-android/src/main/java/com/instacart/formula/android/FragmentFlowStoreImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package com.instacart.formula.android | ||
|
||
import com.instacart.formula.Evaluation | ||
import com.instacart.formula.Formula | ||
import com.instacart.formula.RuntimeConfig | ||
import com.instacart.formula.Snapshot | ||
import com.instacart.formula.android.internal.Binding | ||
import com.instacart.formula.android.events.FragmentLifecycleEvent | ||
import com.instacart.formula.android.internal.FeatureObservableAction | ||
import com.instacart.formula.android.internal.forEachIndices | ||
import com.instacart.formula.android.utils.MainThreadDispatcher | ||
import com.instacart.formula.rxjava3.RxAction | ||
import com.instacart.formula.rxjava3.toObservable | ||
import com.jakewharton.rxrelay3.PublishRelay | ||
import io.reactivex.rxjava3.core.Observable | ||
|
||
/** | ||
* A FragmentFlowStore is responsible for managing the state of multiple [FragmentKey] instances. | ||
*/ | ||
@PublishedApi | ||
internal class FragmentFlowStoreImpl<in Component> @PublishedApi internal constructor( | ||
private val component: Component, | ||
private val bindings: List<Binding<Component>>, | ||
) : FragmentFlowStore() { | ||
private val lifecycleEvents = PublishRelay.create<FragmentLifecycleEvent>() | ||
private val visibleContractEvents = PublishRelay.create<FragmentId>() | ||
private val hiddenContractEvents = PublishRelay.create<FragmentId>() | ||
|
||
private val lifecycleEventStream = RxAction.fromObservable { lifecycleEvents } | ||
private val visibleContractEventStream = RxAction.fromObservable { visibleContractEvents } | ||
private val hiddenContractEventStream = RxAction.fromObservable { hiddenContractEvents } | ||
|
||
private val formula = object : Formula<FragmentEnvironment, FragmentFlowState, FragmentFlowState>() { | ||
override fun initialState(input: FragmentEnvironment): FragmentFlowState = FragmentFlowState() | ||
|
||
override fun Snapshot<FragmentEnvironment, FragmentFlowState>.evaluate(): Evaluation<FragmentFlowState> { | ||
val rootInput = Binding.Input( | ||
environment = input, | ||
component = component, | ||
activeFragments = state.activeIds, | ||
onInitializeFeature = context.onEvent { event -> | ||
val features = state.features.plus(event.id to event) | ||
transition(state.copy(features = features)) | ||
} | ||
) | ||
|
||
bindings.forEachIndices { | ||
it.bind(context, rootInput) | ||
} | ||
|
||
return Evaluation( | ||
output = state, | ||
actions = context.actions { | ||
lifecycleEventStream.onEvent { event -> | ||
val fragmentId = event.fragmentId | ||
when (event) { | ||
is FragmentLifecycleEvent.Removed -> { | ||
val updated = state.copy( | ||
activeIds = state.activeIds.minus(fragmentId), | ||
states = state.states.minus(fragmentId), | ||
features = state.features.minus(fragmentId) | ||
) | ||
transition(updated) | ||
} | ||
is FragmentLifecycleEvent.Added -> { | ||
if (!state.activeIds.contains(fragmentId)) { | ||
if (binds(fragmentId.key)) { | ||
val updated = state.copy(activeIds = state.activeIds.plus(fragmentId)) | ||
transition(updated) | ||
} else { | ||
val updated = state.copy( | ||
activeIds = state.activeIds.plus(fragmentId), | ||
features = state.features.plus(fragmentId to FeatureEvent.MissingBinding(fragmentId)) | ||
) | ||
transition(updated) | ||
} | ||
} else { | ||
none() | ||
} | ||
} | ||
} | ||
} | ||
|
||
visibleContractEventStream.onEvent { | ||
if (state.visibleIds.contains(it)) { | ||
// TODO: should we log this duplicate visibility event? | ||
none() | ||
} else { | ||
transition(state.copy(visibleIds = state.visibleIds.plus(it))) | ||
} | ||
} | ||
|
||
hiddenContractEventStream.onEvent { | ||
transition(state.copy(visibleIds = state.visibleIds.minus(it))) | ||
} | ||
|
||
state.features.entries.forEach { entry -> | ||
val fragmentId = entry.key | ||
val feature = (entry.value as? FeatureEvent.Init)?.feature | ||
if (feature != null) { | ||
val action = FeatureObservableAction( | ||
fragmentEnvironment = input, | ||
fragmentId = fragmentId, | ||
feature = feature, | ||
) | ||
action.onEvent { | ||
if (state.activeIds.contains(fragmentId)) { | ||
val keyState = FragmentState(fragmentId.key, it) | ||
transition(state.copy(states = state.states.plus(fragmentId to keyState))) | ||
} else { | ||
none() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
) | ||
} | ||
} | ||
|
||
override fun onLifecycleEffect(event: FragmentLifecycleEvent) { | ||
lifecycleEvents.accept(event) | ||
} | ||
|
||
override fun onVisibilityChanged(contract: FragmentId, visible: Boolean) { | ||
if (visible) { | ||
visibleContractEvents.accept(contract) | ||
} else { | ||
hiddenContractEvents.accept(contract) | ||
} | ||
} | ||
|
||
override fun state(environment: FragmentEnvironment): Observable<FragmentFlowState> { | ||
val config = RuntimeConfig( | ||
defaultDispatcher = MainThreadDispatcher(), | ||
) | ||
return formula.toObservable(environment, config) | ||
} | ||
|
||
private fun binds(key: Any): Boolean { | ||
bindings.forEachIndices { | ||
if (it.binds(key)) return true | ||
} | ||
return false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 0 additions & 52 deletions
52
formula-android/src/main/java/com/instacart/formula/android/internal/CompositeBinding.kt
This file was deleted.
Oops, something went wrong.