diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index 9d176321ca..fed9649c85 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -35,7 +35,6 @@ import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push import com.bumble.appyx.navmodel.backstack.operation.replace -import com.bumble.appyx.navmodel.backstack.operation.singleTop import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode @@ -60,6 +59,7 @@ import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.architecture.waitForNavTargetAttached import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SessionScope @@ -363,25 +363,15 @@ class LoggedInFlowNode @AssistedInject constructor( } } - suspend fun attachRoomList() { - if (!canShowRoomList()) return - attachChild { - backstack.singleTop(NavTarget.RoomList) - } - } - suspend fun attachRoom(roomId: RoomId) { - if (!canShowRoomList()) return + waitForNavTargetAttached { navTarget -> + navTarget is NavTarget.RoomList + } attachChild { - backstack.singleTop(NavTarget.RoomList) backstack.push(NavTarget.Room(roomId.toRoomIdOrAlias())) } } - private fun canShowRoomList(): Boolean { - return ftueService.state.value is FtueState.Complete - } - @Composable override fun View(modifier: Modifier) { Box(modifier = modifier) { diff --git a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt index a3cbfb7d77..7f06f2833b 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -288,7 +288,7 @@ class RootFlowNode @AssistedInject constructor( .attachSession() .apply { when (deeplinkData) { - is DeeplinkData.Root -> attachRoomList() + is DeeplinkData.Root -> Unit // The room list will always be shown, observing FtueState is DeeplinkData.Room -> attachRoom(deeplinkData.roomId) } } diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/ParentNodeExt.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/ParentNodeExt.kt index c03ff64f6c..4ddd8c78a4 100644 --- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/ParentNodeExt.kt +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/ParentNodeExt.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.lifecycleScope import com.bumble.appyx.core.children.nodeOrNull import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.ParentNode +import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlin.coroutines.resume @@ -48,3 +49,23 @@ suspend inline fun ParentNode.wai continuation.cancel() } } + +/** + * Wait for a child to be attached to the parent node, only using the NavTarget + */ +suspend inline fun ParentNode.waitForNavTargetAttached(crossinline predicate: (NavTarget) -> Boolean) = + suspendCancellableCoroutine { continuation -> + lifecycleScope.launch { + children.collect { childMap -> + val node = childMap.entries + .map { it.key.navTarget } + .lastOrNull(predicate) + if (node != null && !continuation.isCompleted) { + continuation.resume(Unit) + cancel() + } + } + }.invokeOnCompletion { + continuation.cancel() + } + }