Skip to content

Commit

Permalink
Removing FlowFactory and Flow.
Browse files Browse the repository at this point in the history
  • Loading branch information
Laimiux committed Sep 3, 2024
1 parent ff581b2 commit 2dd6ea3
Show file tree
Hide file tree
Showing 18 changed files with 35 additions and 468 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- 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`

## [0.7.1] - June 28, 2022
- **Breaking**: Rename `FragmentBindingBuilder` to `FragmentStoreBuilder`
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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.CompositeBinding
import com.instacart.formula.android.internal.FeatureObservableAction
import com.instacart.formula.android.utils.MainThreadDispatcher
import com.instacart.formula.rxjava3.RxAction
Expand All @@ -17,7 +18,7 @@ import io.reactivex.rxjava3.core.Observable
* A FragmentFlowStore is responsible for managing the state of multiple [FragmentKey] instances.
*/
class FragmentFlowStore @PublishedApi internal constructor(
private val root: Binding<Unit>
private val root: CompositeBinding<*>,
) : Formula<FragmentEnvironment, FragmentFlowState, FragmentFlowState>() {
companion object {
inline fun init(
Expand All @@ -30,12 +31,8 @@ class FragmentFlowStore @PublishedApi internal constructor(
rootComponent: Component,
crossinline contracts: FragmentStoreBuilder<Component>.() -> Unit
): FragmentFlowStore {
val factory: (Unit) -> DisposableScope<Component> = {
DisposableScope(component = rootComponent, onDispose = {})
}

val bindings = FragmentStoreBuilder.build(contracts)
val root = Binding.composite(factory, bindings)
val root = CompositeBinding(rootComponent, bindings.bindings)
return FragmentFlowStore(root)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import java.lang.IllegalStateException
import kotlin.reflect.KClass

/**
* A class used by [FragmentFlowStore] and [Flow] to register [fragment keys][FragmentKey] and their
* A class used by [FragmentFlowStore] to register [fragment keys][FragmentKey] and their
* feature factories.
*/
class FragmentStoreBuilder<Component> {
Expand Down Expand Up @@ -94,41 +94,19 @@ class FragmentStoreBuilder<Component> {
bind(Key::class, featureFactory, toDependencies)
}

/**
* Binds a flow factory.
*/
fun bind(flowFactory: FlowFactory<Component, *>) = apply {
val binding = Binding.composite(flowFactory)
bind(binding)
}

/**
* Binds a flow factory.
*/
fun <Dependencies> bind(
flowFactory: FlowFactory<Dependencies, *>,
toDependencies: (Component) -> Dependencies
) = apply {
val binding = Binding.composite(flowFactory, toDependencies)
bind(binding)
}

@PublishedApi
internal fun build(): Bindings<Component> {
return Bindings(
types = types,
bindings = bindings
)
}

private fun bind(binding: Binding<Component>) = apply {
binding.types().forEach {
if (types.contains(it)) {
throw IllegalStateException("Binding for $it already exists")
}
types += it
val type = binding.type()
if (types.contains(type)) {
throw IllegalStateException("Binding for $type already exists")
}

types += type
bindings += binding
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.instacart.formula.android.internal

import com.instacart.formula.FormulaContext
import com.instacart.formula.android.FeatureEvent
import com.instacart.formula.android.FlowFactory
import com.instacart.formula.android.FragmentEnvironment
import com.instacart.formula.android.FragmentId

Expand All @@ -11,45 +10,14 @@ import com.instacart.formula.android.FragmentId
*/
@PublishedApi
internal abstract class Binding<in ParentComponent> {
companion object {
fun <ParentComponent, Component> composite(
flowFactory: FlowFactory<ParentComponent, Component>,
): Binding<ParentComponent> {
return composite(
flowFactory::createComponent,
flowFactory.createFlow().bindings
)
}

fun <ParentComponent, Dependencies, Component> composite(
flowFactory: FlowFactory<Dependencies, Component>,
toDependencies: (ParentComponent) -> Dependencies,
): Binding<ParentComponent> {
return composite(
scopeFactory = { component ->
val dependencies = toDependencies(component)
flowFactory.createComponent(dependencies)
},
flowFactory.createFlow().bindings
)
}

@PublishedApi internal fun <ParentComponent, Component> composite(
scopeFactory: ComponentFactory<ParentComponent, Component>,
bindings: Bindings<Component>
): Binding<ParentComponent> {
return CompositeBinding(scopeFactory, bindings.types, bindings.bindings)
}
}

data class Input<out Component>(
val environment: FragmentEnvironment,
val component: Component,
val activeFragments: List<FragmentId>,
val onInitializeFeature: (FeatureEvent) -> Unit,
)

internal abstract fun types(): Set<Class<*>>
internal abstract fun type(): Class<*>

/**
* Returns true if this binding handles this [key]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.instacart.formula.android.internal

@PublishedApi
internal class Bindings<in Component>(
val types: Set<Class<*>>,
val bindings: List<Binding<Component>>
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.instacart.formula.android.internal

import com.instacart.formula.Action
import com.instacart.formula.Evaluation
import com.instacart.formula.Formula
import com.instacart.formula.FormulaContext
import com.instacart.formula.Snapshot
import com.instacart.formula.android.DisposableScope
import com.instacart.formula.StatelessFormula
import com.instacart.formula.android.internal.Binding.Input

/**
* Defines how a group of keys should be bound to their integrations.
Expand All @@ -14,71 +13,40 @@ import com.instacart.formula.android.DisposableScope
* @param ScopedComponent A component that is initialized when user enters this flow and is shared between
* all the screens within the flow. Component will be destroyed when user exists the flow.
*/
internal class CompositeBinding<ParentComponent, ScopedComponent>(
private val scopeFactory: ComponentFactory<ParentComponent, ScopedComponent>,
private val types: Set<Class<*>>,
@PublishedApi
internal class CompositeBinding<ScopedComponent>(
private val component: ScopedComponent,
private val bindings: List<Binding<ScopedComponent>>
) : Binding<ParentComponent>() {
) {

data class State<ScopedComponent>(
val component: DisposableScope<ScopedComponent>? = null
)
private val formula = object : StatelessFormula<Input<Unit>, Unit>() {
override fun key(input: Input<Unit>): Any = this

private val formula = object : Formula<Input<ParentComponent>, State<ScopedComponent>, Unit>() {
override fun key(input: Input<ParentComponent>): Any? = this

override fun initialState(input: Input<ParentComponent>): State<ScopedComponent> {
return State()
}

override fun Snapshot<Input<ParentComponent>, State<ScopedComponent>>.evaluate(): Evaluation<Unit> {
val component = state.component
if (component != null) {
val childInput = Input(
environment = input.environment,
component = component.component,
activeFragments = input.activeFragments,
onInitializeFeature = input.onInitializeFeature,
)
bindings.forEachIndices {
it.bind(context, childInput)
}
override fun Snapshot<Input<Unit>, Unit>.evaluate(): Evaluation<Unit> {
val childInput = Input(
environment = input.environment,
component = component,
activeFragments = input.activeFragments,
onInitializeFeature = input.onInitializeFeature,
)
bindings.forEachIndices {
it.bind(context, childInput)
}
return Evaluation(
output = Unit,
actions = context.actions {
val isInScope = input.activeFragments.any { binds(it.key) }
Action.onData(isInScope).onEvent {
if (isInScope && component == null) {
transition(State(component = scopeFactory.invoke(input.component)))
} else if (!isInScope && component != null) {
transition(State<ScopedComponent>()) {
component.dispose()
}
} else {
none()
}
}

Action.onTerminate().onEvent {
transition { component?.dispose() }
}
}
)
}
}


override fun types(): Set<Class<*>> = types

override fun binds(key: Any): Boolean {
fun binds(key: Any): Boolean {
bindings.forEachIndices {
if (it.binds(key)) return true
}
return false
}

override fun bind(context: FormulaContext<*, *>, input: Input<ParentComponent>) {
fun bind(context: FormulaContext<*, *>, input: Input<Unit>) {
context.child(formula, input)
}
}
Loading

0 comments on commit 2dd6ea3

Please sign in to comment.