Last active
November 23, 2022 02:24
-
-
Save RationalRank/c7e493ac04aa0567c6f1cd65f709335b to your computer and use it in GitHub Desktop.
Appyx NodeConnector - Using kotlin flow
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
class NodeConnector<Input, Output> : Connectable<Input, Output> { | |
private val inputChannel: Channel<Input> = Channel(Channel.BUFFERED) | |
private val outputChannel: Channel<Output> = Channel(Channel.BUFFERED) | |
override val input: Flow<Input> = inputChannel.receiveAsFlow() | |
override val output: Flow<Output> = outputChannel.receiveAsFlow() | |
override fun send(value: Output) { | |
outputChannel.trySend(value) | |
} | |
override fun accept(value: Input) { | |
inputChannel.trySend(value) | |
} | |
} | |
interface Connectable<Input, Output> : NodeLifecycleAware { | |
val input: Flow<Input> | |
val output: Flow<Output> | |
// Send an output | |
fun send(value: Output) | |
// Accept an input | |
fun accept(value: Input) | |
} | |
inline fun <reified Input, reified Output> NodeConnector<Input, Output>.forEachOutput( | |
lifecycleOwner: LifecycleOwner, | |
crossinline onOutputReceived: (output: Output) -> Unit | |
) { | |
output | |
.onEach { onOutputReceived(it) } | |
.launchIn(lifecycleOwner.lifecycleScope) | |
} | |
inline fun <reified Input, reified Output> NodeConnector<Input, Output>.forEachInput( | |
lifecycleOwner: LifecycleOwner, | |
crossinline onInputReceived: (output: Input) -> Unit | |
) { | |
input | |
.onEach { onInputReceived(it) } | |
.launchIn(lifecycleOwner.lifecycleScope) | |
} |
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
class ParentNode( | |
buildContext: BuildContext, | |
private val listBackStack: BackStack<Routing> | |
) : ParentNode<ParentNode.Routing>(listBackStack, buildContext) { | |
sealed interface Routing : Parcelable { | |
@Parcelize | |
object List : Routing | |
@Parcelize | |
object Detail : Routing | |
} | |
private val listConnection: NodeConnector<ListNode.Inputs, ListNode.Outputs> = NodeConnector() | |
private val detailConnection: NodeConnector<DetailNode.Inputs, DetailNode.Outputs> = NodeConnector() | |
init { | |
listConnection.forEachOutput(this) { output -> | |
if (output is ListNode.Outputs.ItemSelected) { | |
listBackStack.singleTop(Routing.Detail) | |
detailConnection.accept(DetailNode.Inputs.ViewItem(output.itemUid, output.name)) | |
} | |
} | |
} | |
} | |
class DetailNode( | |
buildContext: BuildContext, | |
) : Node(buildContext) { | |
sealed class Inputs { | |
data class ViewItem(val itemUid: String, val name: String) : Inputs() | |
} | |
init { | |
nodeConnector.forEachInput(this@DetailNode) { input -> | |
if (input is Inputs.ViewItem) { | |
viewModel.updateItem(input.itemUid, input.name) | |
} | |
} | |
} | |
@Composable | |
override fun View(modifier: Modifier) { | |
DetailScreen(modifier, viewModel) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment