Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename ParentNode & Node to Node and LeafNode #657

Merged
merged 20 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ Please refer to [2.0.0-alpha10 – Migration guide](2.0.0-alpha10.md)
- [#642](https://github.com/bumble-tech/appyx/pull/642) – Renamings
- [#643](https://github.com/bumble-tech/appyx/pull/643) – Unify AppyxComponent composable between appyx-navigation and appyx-interactions modules
- [#651](https://github.com/bumble-tech/appyx/pull/651) - Keep only one instance of SaveStateMap typealias and moved it to `com.bumble.appyx.utils.multiplatform` package
- [#654](https://github.com/bumble-tech/appyx/pull/654) - Renamings
- [#652](https://github.com/bumble-tech/appyx/pull/652) - KSP processor renamed from `mutable-ui-processor` to `appyx-processor`
- [#654](https://github.com/bumble-tech/appyx/pull/654) - Renamings
- [#657](https://github.com/bumble-tech/appyx/pull/657) - Rename ParentNode & Node to Node and LeafNode

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.bumble.appyx.utils.testing.ui.rules.AppyxTestActivity
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

class AppyxTestScenario<T : Node>(
class AppyxTestScenario<T : Node<*>>(
private val composeTestRule: ComposeTestRule = createEmptyComposeRule(),
/** Add decorations like custom theme or CompositionLocalProvider. Do not forget to invoke `content()`. */
private val decorator: (@Composable (content: @Composable () -> Unit) -> Unit) = { content -> content() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.bumble.appyx.navigation.AppyxTestScenario
import com.bumble.appyx.navigation.children.nodeOrNull
import com.bumble.appyx.navigation.composable.PermanentChild
import com.bumble.appyx.navigation.modality.NodeContext
import com.bumble.appyx.navigation.node.PermanentChildTest.TestParentNode.Child
import com.bumble.appyx.navigation.node.PermanentChildTest.TestNode.Child
import com.bumble.appyx.utils.multiplatform.Parcelable
import com.bumble.appyx.utils.multiplatform.Parcelize
import org.junit.Assert.assertEquals
Expand All @@ -22,8 +22,8 @@ import org.junit.Test

class PermanentChildTest {

var nodeFactory: (nodeContext: NodeContext) -> TestParentNode = {
TestParentNode(nodeContext = it)
var nodeFactory: (nodeContext: NodeContext) -> TestNode = {
TestNode(nodeContext = it)
}

@get:Rule
Expand Down Expand Up @@ -65,7 +65,7 @@ class PermanentChildTest {

private fun createPermanentAppyxComponentWithInteractionKey() {
nodeFactory = {
TestParentNode(
TestNode(
nodeContext = it,
permanentAppyxComponent = PermanentAppyxComponent(
savedStateMap = null,
Expand All @@ -76,11 +76,11 @@ class PermanentChildTest {

}

class TestParentNode(
class TestNode(
nodeContext: NodeContext,
private val permanentAppyxComponent: PermanentAppyxComponent<Child> =
PermanentAppyxComponent(savedStateMap = nodeContext.savedStateMap)
) : ParentNode<Child>(
) : Node<Child>(
nodeContext = nodeContext,
appyxComponent = permanentAppyxComponent
) {
Expand All @@ -90,7 +90,7 @@ class PermanentChildTest {

var renderPermanentChild by mutableStateOf(true)

override fun buildChildNode(navTarget: Child, nodeContext: NodeContext): Node =
override fun buildChildNode(navTarget: Child, nodeContext: NodeContext): Node<*> =
node(nodeContext) { modifier ->
BasicText(
text = navTarget.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import com.bumble.appyx.utils.customisations.NodeCustomisationDirectoryImpl


/**
* Composable function to host [Node].
* Composable function to host [Node<*>].
*
* This wrapper uses [LocalConfiguration] to provide [ScreenSize] automatically.
*/
@Suppress("ComposableParamOrder") // detekt complains as 'factory' param isn't a pure lambda
@Composable
fun <N : Node> NodeHost(
fun <N : Node<*>> NodeHost(
lifecycle: Lifecycle,
integrationPoint: IntegrationPoint,
modifier: Modifier = Modifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package com.bumble.appyx.navigation.node

import com.bumble.appyx.navigation.platform.PlatformLifecycleRegistry

val Node.androidLifecycle: androidx.lifecycle.Lifecycle
val Node<*>.androidLifecycle: androidx.lifecycle.Lifecycle
get() = (lifecycle as PlatformLifecycleRegistry).androidLifecycleRegistry
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import com.bumble.appyx.navigation.node.Node
// Changing this to an interface would be a breaking change
@Suppress("UnnecessaryAbstractClass")
abstract class Builder<P> {
abstract fun build(nodeContext: NodeContext, payload: P): Node
abstract fun build(nodeContext: NodeContext, payload: P): Node<*>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import com.bumble.appyx.navigation.node.Node
// Changing this to an interface would be a breaking change
@Suppress("UnnecessaryAbstractClass")
abstract class SimpleBuilder {
abstract fun build(nodeContext: NodeContext): Node
abstract fun build(nodeContext: NodeContext): Node<*>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.bumble.appyx.navigation.node.Node
import com.bumble.appyx.navigation.plugin.NodeAware
import kotlin.reflect.KClass

interface ChildAware<N: Node> : NodeAware<N> {
interface ChildAware<N: Node<*>> : NodeAware<N> {

fun <T : Any> whenChildAttached(
child: KClass<T>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import kotlin.reflect.safeCast

internal sealed class ChildAwareCallbackInfo {

abstract fun onRegistered(activeNodes: List<Node>)
abstract fun onRegistered(activeNodes: List<Node<*>>)

class Single<T : Any>(
private val child: KClass<T>,
private val callback: ChildCallback<T>,
private val parentLifecycle: Lifecycle,
) : ChildAwareCallbackInfo() {

fun onNewNodeAppeared(newNode: Node) {
fun onNewNodeAppeared(newNode: Node<*>) {
if (parentLifecycle.isDestroyed) return
val castedNode = child.safeCast(newNode)
if (castedNode != null) {
Expand All @@ -31,7 +31,7 @@ internal sealed class ChildAwareCallbackInfo {
}
}

override fun onRegistered(activeNodes: List<Node>) {
override fun onRegistered(activeNodes: List<Node<*>>) {
activeNodes.forEach { node ->
onNewNodeAppeared(node)
}
Expand All @@ -47,17 +47,17 @@ internal sealed class ChildAwareCallbackInfo {
) : ChildAwareCallbackInfo() {

fun onNewNodeAppeared(
activeNodes: Collection<Node>,
newNode: Node,
ignoreNodes: Set<Node>,
activeNodes: Collection<Node<*>>,
newNode: Node<*>,
ignoreNodes: Set<Node<*>>,
) {
val second = getOther(newNode) ?: return
activeNodes
.filter { second.isInstance(it) && it != newNode && it !in ignoreNodes }
.forEach { notify(newNode, it) }
}

override fun onRegistered(activeNodes: List<Node>) {
override fun onRegistered(activeNodes: List<Node<*>>) {
activeNodes.forEachIndexed { index, node ->
onNewNodeAppeared(
// Do not include already handled nodes to avoid call duplication
Expand All @@ -68,7 +68,7 @@ internal sealed class ChildAwareCallbackInfo {
}
}

private fun notify(node1: Node, node2: Node) {
private fun notify(node1: Node<*>, node2: Node<*>) {
if (parentLifecycle.isDestroyed) return
val lifecycle =
MinimumCombinedLifecycle(
Expand All @@ -83,7 +83,7 @@ internal sealed class ChildAwareCallbackInfo {
}
}

private fun getOther(node: Node): KClass<*>? =
private fun getOther(node: Node<*>): KClass<*>? =
when {
child1.isInstance(node) -> child2
child2.isInstance(node) -> child1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package com.bumble.appyx.navigation.children

import com.bumble.appyx.navigation.node.Node

inline fun <reified T : Node> ChildAware<*>.whenChildAttached(
inline fun <reified T : Node<*>> ChildAware<*>.whenChildAttached(
noinline callback: ChildCallback<T>,
) {
whenChildAttached(T::class, callback)
}

inline fun <reified T1 : Node, reified T2 : Node> ChildAware<*>.whenChildrenAttached(
inline fun <reified T1 : Node<*>, reified T2 : Node<*>> ChildAware<*>.whenChildrenAttached(
noinline callback: ChildrenCallback<T1, T2>,
) {
whenChildrenAttached(T1::class, T2::class, callback)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import com.bumble.appyx.interactions.core.Element
import com.bumble.appyx.navigation.lifecycle.DefaultPlatformLifecycleObserver
import com.bumble.appyx.navigation.lifecycle.Lifecycle
import com.bumble.appyx.navigation.lifecycle.isDestroyed
import com.bumble.appyx.navigation.node.LeafNode
import com.bumble.appyx.navigation.node.Node
import com.bumble.appyx.navigation.node.ParentNode
import com.bumble.appyx.navigation.withPrevious
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -14,7 +14,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlin.reflect.KClass

class ChildAwareImpl<N : Node> : ChildAware<N> {
class ChildAwareImpl<N : Node<*>> : ChildAware<N> {

private val callbacks: MutableList<ChildAwareCallbackInfo> = ArrayList()

Expand All @@ -29,11 +29,11 @@ class ChildAwareImpl<N : Node> : ChildAware<N> {
this.node = node
lifecycle = node.lifecycle
coroutineScope = lifecycle.coroutineScope
if (node is ParentNode<*>) {
if (node is LeafNode) {
children = MutableStateFlow(emptyMap())
} else {
children = node.children
coroutineScope.launch { observeChanges() }
} else {
children = MutableStateFlow(emptyMap())
}
}

Expand All @@ -43,7 +43,7 @@ class ChildAwareImpl<N : Node> : ChildAware<N> {
.withPrevious()
.collect { (previous, current) ->
val newNodes = current - previous.orEmpty()
val visitedSet = HashSet<Node>()
val visitedSet = HashSet<Node<*>>()
newNodes.forEach { node ->
notifyWhenChanged(node, current, visitedSet)
visitedSet.add(node)
Expand Down Expand Up @@ -78,7 +78,7 @@ class ChildAwareImpl<N : Node> : ChildAware<N> {
callback.onRegistered(getCreatedNodes(children.value))
}

private fun notifyWhenChanged(child: Node, nodes: Collection<Node>, ignore: Set<Node>) {
private fun notifyWhenChanged(child: Node<*>, nodes: Collection<Node<*>>, ignore: Set<Node<*>>) {
for (callback in callbacks) {
when (callback) {
is ChildAwareCallbackInfo.Double<*, *> -> callback.onNewNodeAppeared(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ sealed class ChildEntry<T> {
/** All public APIs should return this type of child which is ready to work with. */
class Initialized<T>(
override val key: Element<T>,
val node: Node,
val node: Node<*>,
) : ChildEntry<T>()

class Suspended<T>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.bumble.appyx.navigation.children

import com.bumble.appyx.navigation.node.Node

val <T> ChildEntry<T>.nodeOrNull: Node?
val <T> ChildEntry<T>.nodeOrNull: Node<*>?
get() =
when (this) {
is ChildEntry.Initialized -> node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ import com.bumble.appyx.navigation.node.Node

fun interface ChildNodeBuilder<NavTarget> {

fun buildChildNode(navTarget: NavTarget, nodeContext: NodeContext): Node
fun buildChildNode(navTarget: NavTarget, nodeContext: NodeContext): Node<*>
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.bumble.appyx.interactions.core.Element
import com.bumble.appyx.interactions.core.state.MutableSavedStateMap
import com.bumble.appyx.navigation.modality.AncestryInfo
import com.bumble.appyx.navigation.modality.NodeContext
import com.bumble.appyx.navigation.node.ParentNode
import com.bumble.appyx.navigation.node.Node
import com.bumble.appyx.navigation.node.build
import com.bumble.appyx.utils.multiplatform.SavedStateMap
import com.bumble.appyx.utils.customisations.NodeCustomisationDirectory
Expand All @@ -25,23 +25,23 @@ internal class ChildNodeCreationManager<NavTarget : Any>(
private val customisations: NodeCustomisationDirectory,
private val keepMode: ChildEntry.KeepMode,
) {
private lateinit var parentNode: ParentNode<NavTarget>
private lateinit var node: Node<NavTarget>
private val _children =
MutableStateFlow<Map<Element<NavTarget>, ChildEntry<NavTarget>>>(emptyMap())
val children: StateFlow<ChildEntryMap<NavTarget>> = _children.asStateFlow()

fun launch(parentNode: ParentNode<NavTarget>) {
this.parentNode = parentNode
fun launch(node: Node<NavTarget>) {
this.node = node
savedStateMap.restoreChildren()?.also { restoredMap ->
_children.update { restoredMap }
savedStateMap = null
}
syncAppyxComponentWithChildren(parentNode)
syncAppyxComponentWithChildren(node)
}

private fun syncAppyxComponentWithChildren(parentNode: ParentNode<NavTarget>) {
parentNode.lifecycle.coroutineScope.launch {
parentNode.appyxComponent.elements.collect { state ->
private fun syncAppyxComponentWithChildren(node: Node<NavTarget>) {
node.lifecycle.coroutineScope.launch {
node.appyxComponent.elements.collect { state ->
val appyxComponentKeepKeys: Set<Element<NavTarget>>
val appyxComponentSuspendKeys: Set<Element<NavTarget>>
val appyxComponentKeys: Set<Element<NavTarget>>
Expand Down Expand Up @@ -165,9 +165,9 @@ internal class ChildNodeCreationManager<NavTarget : Any>(

private fun childContext(savedState: SavedStateMap?): NodeContext =
NodeContext(
ancestryInfo = AncestryInfo.Child(parentNode),
ancestryInfo = AncestryInfo.Child(node),
savedStateMap = savedState,
customisations = customisations.getSubDirectoryOrSelf(parentNode::class),
customisations = customisations.getSubDirectoryOrSelf(node::class),
)

private fun childEntry(
Expand All @@ -180,7 +180,7 @@ internal class ChildNodeCreationManager<NavTarget : Any>(
} else {
ChildEntry.Initialized(
key = key,
node = parentNode
node = node
.buildChildNode(key.interactionTarget, childContext(savedState))
.build()
)
Expand All @@ -192,7 +192,7 @@ internal class ChildNodeCreationManager<NavTarget : Any>(
is ChildEntry.Suspended ->
ChildEntry.Initialized(
key = key,
node = parentNode.buildChildNode(
node = node.buildChildNode(
navTarget = key.interactionTarget,
nodeContext = childContext(savedState),
).build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.bumble.appyx.navigation.node.Node
import com.bumble.appyx.navigation.plugin.NodeAware
import com.bumble.appyx.navigation.plugin.NodeLifecycleAware

open class Interactor<N : Node>(
open class Interactor<N : Node<*>>(
private val childAwareImpl: ChildAware<N> = ChildAwareImpl()
) : NodeAware<N>,
NodeLifecycleAware,
Expand Down
Loading