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 d1e3447570..a23a5b9425 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -57,7 +57,8 @@ import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.features.roomlist.api.RoomListEntryPoint import io.element.android.features.securebackup.api.SecureBackupEntryPoint import io.element.android.features.verifysession.api.VerifySessionEntryPoint -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.waitForChildAttached @@ -100,7 +101,7 @@ class LoggedInFlowNode @AssistedInject constructor( private val lockScreenStateService: LockScreenService, private val matrixClient: MatrixClient, snackbarDispatcher: SnackbarDispatcher, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.RoomList, savedStateMap = buildContext.savedStateMap, @@ -384,12 +385,7 @@ class LoggedInFlowNode @AssistedInject constructor( override fun View(modifier: Modifier) { Box(modifier = modifier) { val lockScreenState by lockScreenStateService.lockState.collectAsState() - Children( - navModel = backstack, - modifier = Modifier, - // Animate navigation to settings and to a room - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() val isFtueDisplayed by ftueState.shouldDisplayFlow.collectAsState() if (!isFtueDisplayed) { PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt index 6c22644658..42efc4a15b 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt @@ -33,7 +33,8 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.features.login.api.LoginEntryPoint import io.element.android.features.onboarding.api.OnBoardingEntryPoint import io.element.android.features.preferences.api.ConfigureTracingEntryPoint -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.di.AppScope import io.element.android.libraries.matrix.ui.media.NotLoggedInImageLoaderFactory @@ -47,7 +48,7 @@ class NotLoggedInFlowNode @AssistedInject constructor( private val configureTracingEntryPoint: ConfigureTracingEntryPoint, private val loginEntryPoint: LoginEntryPoint, private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.OnBoarding, savedStateMap = buildContext.savedStateMap @@ -111,11 +112,6 @@ class NotLoggedInFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - // Animate navigation to login screen - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } 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 c3b30f0f54..6d450d2ef6 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt @@ -46,7 +46,8 @@ import io.element.android.features.login.api.oidc.OidcAction import io.element.android.features.login.api.oidc.OidcActionFlow import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint import io.element.android.features.signedout.api.SignedOutEntryPoint -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.waitForChildAttached @@ -74,7 +75,7 @@ class RootFlowNode @AssistedInject constructor( private val signedOutEntryPoint: SignedOutEntryPoint, private val intentResolver: IntentResolver, private val oidcActionFlow: OidcActionFlow, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.SplashScreen, savedStateMap = buildContext.savedStateMap, @@ -172,11 +173,7 @@ class RootFlowNode @AssistedInject constructor( modifier = modifier, onOpenBugReport = this::onOpenBugReport, ) { - Children( - navModel = backstack, - // Animate opening the bug report screen - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt index c3df0f0ee2..9f1b333804 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomFlowNode.kt @@ -38,7 +38,8 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkStatus -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs @@ -57,7 +58,7 @@ class RoomFlowNode @AssistedInject constructor( loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory, private val networkMonitor: NetworkMonitor, ) : - BackstackNode( + BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Loading, savedStateMap = buildContext.savedStateMap, @@ -130,10 +131,7 @@ class RoomFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - ) + BackstackView() } } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt index 3cc405d7fd..c72a743de9 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt @@ -35,7 +35,8 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.appnav.di.RoomComponentFactory import io.element.android.features.messages.api.MessagesEntryPoint import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.inputs @@ -64,7 +65,7 @@ class RoomLoadedFlowNode @AssistedInject constructor( private val appCoroutineScope: CoroutineScope, roomComponentFactory: RoomComponentFactory, roomMembershipObserver: RoomMembershipObserver, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance(Inputs::class.java).first().initialElement, savedStateMap = buildContext.savedStateMap, @@ -202,10 +203,6 @@ class RoomLoadedFlowNode @AssistedInject constructor( } } } - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt index 98ee988faa..459e9b976d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/ConfigureRoomFlowNode.kt @@ -32,7 +32,8 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.features.createroom.impl.addpeople.AddPeopleNode import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.features.createroom.impl.di.CreateRoomComponent -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.createNode @@ -45,7 +46,7 @@ class ConfigureRoomFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, ) : DaggerComponentOwner, - BackstackNode( + BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap, @@ -88,10 +89,6 @@ class ConfigureRoomFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler() - ) + BackstackView() } } diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt index 7ba85f20c2..f0b4b1d1da 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomFlowNode.kt @@ -32,7 +32,8 @@ import io.element.android.anvilannotations.ContributesNode import io.element.android.features.createroom.api.CreateRoomEntryPoint import io.element.android.features.createroom.impl.configureroom.ConfigureRoomNode import io.element.android.features.createroom.impl.root.CreateRoomRootNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope @@ -43,7 +44,7 @@ import kotlinx.parcelize.Parcelize class CreateRoomFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap, @@ -87,10 +88,6 @@ class CreateRoomFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler() - ) + BackstackView() } } diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt index 0b77d5e176..d1eb6af0e5 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/FtueFlowNode.kt @@ -40,7 +40,8 @@ import io.element.android.features.ftue.impl.state.DefaultFtueState import io.element.android.features.ftue.impl.state.FtueStep import io.element.android.features.ftue.impl.welcome.WelcomeNode import io.element.android.features.lockscreen.api.LockScreenEntryPoint -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.AppScope @@ -62,7 +63,7 @@ class FtueFlowNode @AssistedInject constructor( private val analyticsEntryPoint: AnalyticsEntryPoint, private val analyticsService: AnalyticsService, private val lockScreenEntryPoint: LockScreenEntryPoint, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Placeholder, savedStateMap = buildContext.savedStateMap, @@ -181,11 +182,7 @@ class FtueFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } @ContributesNode(AppScope::class) diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt index 4818a51bdc..7cec3810aa 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/LockScreenFlowNode.kt @@ -32,7 +32,8 @@ import io.element.android.features.lockscreen.api.LockScreenEntryPoint import io.element.android.features.lockscreen.impl.settings.LockScreenSettingsFlowNode import io.element.android.features.lockscreen.impl.setup.LockScreenSetupFlowNode import io.element.android.features.lockscreen.impl.unlock.PinUnlockNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode @@ -43,7 +44,7 @@ import kotlinx.parcelize.Parcelize class LockScreenFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance(Inputs::class.java).first().initialNavTarget, savedStateMap = buildContext.savedStateMap, @@ -93,10 +94,6 @@ class LockScreenFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt index dec3699d07..2ed1dd58ea 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsFlowNode.kt @@ -36,7 +36,8 @@ import io.element.android.features.lockscreen.impl.pin.DefaultPinCodeManagerCall import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.setup.pin.SetupPinNode import io.element.android.features.lockscreen.impl.unlock.PinUnlockNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope @@ -49,7 +50,7 @@ class LockScreenSettingsFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val pinCodeManager: PinCodeManager, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Unknown, savedStateMap = buildContext.savedStateMap, @@ -132,10 +133,6 @@ class LockScreenSettingsFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/LockScreenSetupFlowNode.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/LockScreenSetupFlowNode.kt index f612f3b82e..d51a6edeef 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/LockScreenSetupFlowNode.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/setup/LockScreenSetupFlowNode.kt @@ -34,7 +34,8 @@ import io.element.android.features.lockscreen.impl.pin.DefaultPinCodeManagerCall import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.setup.biometric.SetupBiometricNode import io.element.android.features.lockscreen.impl.setup.pin.SetupPinNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope @@ -45,7 +46,7 @@ class LockScreenSetupFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val pinCodeManager: PinCodeManager, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Pin, savedStateMap = buildContext.savedStateMap, @@ -106,10 +107,6 @@ class LockScreenSetupFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt index 89eb6e526e..3ebad4f787 100644 --- a/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt +++ b/features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt @@ -48,7 +48,8 @@ import io.element.android.features.login.impl.screens.loginpassword.LoginFormSta import io.element.android.features.login.impl.screens.loginpassword.LoginPasswordNode import io.element.android.features.login.impl.screens.searchaccountprovider.SearchAccountProviderNode import io.element.android.features.login.impl.screens.waitlistscreen.WaitListNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode @@ -68,7 +69,7 @@ class LoginFlowNode @AssistedInject constructor( private val accountProviderDataSource: AccountProviderDataSource, private val defaultLoginUserStory: DefaultLoginUserStory, private val oidcActionFlow: OidcActionFlow, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.ConfirmAccountProvider, savedStateMap = buildContext.savedStateMap, @@ -217,11 +218,6 @@ class LoginFlowNode @AssistedInject constructor( accountProviderDataSource.reset() } } - Children( - navModel = backstack, - modifier = modifier, - // Animate transition to change server screen - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt index cc9ded778b..acccfeaedc 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt @@ -20,9 +20,9 @@ import android.content.Context import android.os.Parcelable import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.node.node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack @@ -49,9 +49,11 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent import io.element.android.features.poll.api.create.CreatePollEntryPoint import io.element.android.features.poll.api.create.CreatePollMode -import io.element.android.libraries.architecture.BackstackNode -import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler +import io.element.android.libraries.architecture.BackstackWithOverlayBox +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.architecture.overlay.Overlay +import io.element.android.libraries.architecture.overlay.operation.show import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.RoomScope import io.element.android.libraries.matrix.api.MatrixClient @@ -74,16 +76,23 @@ class MessagesFlowNode @AssistedInject constructor( private val sendLocationEntryPoint: SendLocationEntryPoint, private val showLocationEntryPoint: ShowLocationEntryPoint, private val createPollEntryPoint: CreatePollEntryPoint, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Messages, savedStateMap = buildContext.savedStateMap, ), + overlay = Overlay( + savedStateMap = buildContext.savedStateMap, + ), buildContext = buildContext, plugins = plugins ) { sealed interface NavTarget : Parcelable { + + @Parcelize + data object Empty : NavTarget + @Parcelize data object Messages : NavTarget @@ -223,6 +232,9 @@ class MessagesFlowNode @AssistedInject constructor( .params(CreatePollEntryPoint.Params(mode = CreatePollMode.EditPoll(eventId = navTarget.eventId))) .build() } + NavTarget.Empty -> { + node(buildContext) {} + } } } @@ -239,7 +251,7 @@ class MessagesFlowNode @AssistedInject constructor( mediaSource = event.content.mediaSource, thumbnailSource = event.content.thumbnailSource, ) - backstack.push(navTarget) + overlay.show(navTarget) } is TimelineItemVideoContent -> { val navTarget = NavTarget.MediaViewer( @@ -252,7 +264,7 @@ class MessagesFlowNode @AssistedInject constructor( mediaSource = event.content.videoSource, thumbnailSource = event.content.thumbnailSource, ) - backstack.push(navTarget) + overlay.show(navTarget) } is TimelineItemFileContent -> { val navTarget = NavTarget.MediaViewer( @@ -265,7 +277,7 @@ class MessagesFlowNode @AssistedInject constructor( mediaSource = event.content.fileSource, thumbnailSource = event.content.thumbnailSource, ) - backstack.push(navTarget) + overlay.show(navTarget) } is TimelineItemAudioContent -> { val navTarget = NavTarget.MediaViewer( @@ -278,14 +290,14 @@ class MessagesFlowNode @AssistedInject constructor( mediaSource = event.content.mediaSource, thumbnailSource = null, ) - backstack.push(navTarget) + overlay.show(navTarget) } is TimelineItemLocationContent -> { val navTarget = NavTarget.LocationViewer( location = event.content.location, description = event.content.description, ) - backstack.push(navTarget) + overlay.show(navTarget) } else -> Unit } @@ -293,10 +305,6 @@ class MessagesFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackWithOverlayBox(modifier) } } diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt index 425c22e255..0d55c7f186 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryFlowNode.kt @@ -30,7 +30,8 @@ import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode import io.element.android.features.poll.api.create.CreatePollEntryPoint import io.element.android.features.poll.api.create.CreatePollMode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.RoomScope @@ -42,7 +43,7 @@ class PollHistoryFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val createPollEntryPoint: CreatePollEntryPoint, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap, @@ -82,11 +83,7 @@ class PollHistoryFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler() - ) + BackstackView() } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index bd7d961123..0958f2722f 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -41,7 +41,8 @@ import io.element.android.features.preferences.impl.notifications.NotificationSe import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingNode import io.element.android.features.preferences.impl.root.PreferencesRootNode import io.element.android.features.preferences.impl.user.editprofile.EditUserProfileNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope @@ -55,7 +56,7 @@ class PreferencesFlowNode @AssistedInject constructor( @Assisted plugins: List, private val lockScreenEntryPoint: LockScreenEntryPoint, private val logoutEntryPoint: LogoutEntryPoint, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), savedStateMap = buildContext.savedStateMap, @@ -210,10 +211,6 @@ class PreferencesFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler() - ) + BackstackView() } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 0229282319..705ae465fb 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -37,7 +37,8 @@ import io.element.android.features.roomdetails.impl.members.RoomMemberListNode import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsNode import io.element.android.features.roomdetails.impl.members.details.avatar.AvatarPreviewNode import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.core.mimetype.MimeTypes @@ -54,7 +55,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val pollHistoryEntryPoint: PollHistoryEntryPoint, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), savedStateMap = buildContext.savedStateMap, @@ -196,10 +197,6 @@ class RoomDetailsFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler(), - ) + BackstackView() } } diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt index 0ce510336c..7495f89918 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/SecureBackupFlowNode.kt @@ -33,7 +33,8 @@ import io.element.android.features.securebackup.impl.enable.SecureBackupEnableNo import io.element.android.features.securebackup.impl.enter.SecureBackupEnterRecoveryKeyNode import io.element.android.features.securebackup.impl.root.SecureBackupRootNode import io.element.android.features.securebackup.impl.setup.SecureBackupSetupNode -import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.BackstackView +import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.SessionScope @@ -43,7 +44,7 @@ import kotlinx.parcelize.Parcelize class SecureBackupFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, -) : BackstackNode( +) : BaseFlowNode( backstack = BackStack( initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap, @@ -124,10 +125,6 @@ class SecureBackupFlowNode @AssistedInject constructor( @Composable override fun View(modifier: Modifier) { - Children( - navModel = backstack, - modifier = modifier, - transitionHandler = rememberDefaultTransitionHandler() - ) + BackstackView() } } diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt deleted file mode 100644 index deb6d0e63b..0000000000 --- a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BackstackNode.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.element.android.libraries.architecture - -import androidx.compose.runtime.Stable -import com.bumble.appyx.core.children.ChildEntry -import com.bumble.appyx.core.modality.BuildContext -import com.bumble.appyx.core.navigation.model.combined.plus -import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel -import com.bumble.appyx.core.node.Node -import com.bumble.appyx.core.node.ParentNode -import com.bumble.appyx.core.plugin.Plugin -import com.bumble.appyx.navmodel.backstack.BackStack - -/** - * This class is just an helper for configuring a backstack directly in the constructor. - * With this we can more easily use constructor injection without having a secondary constructor to create the [BackStack] instance. - * Can be used instead of [ParentNode] in flow nodes. - */ -@Stable -abstract class BackstackNode( - val backstack: BackStack, - buildContext: BuildContext, - plugins: List, - val permanentNavModel: PermanentNavModel = PermanentNavModel(emptySet(), null), - childKeepMode: ChildEntry.KeepMode = ChildEntry.KeepMode.KEEP, -) : ParentNode( - navModel = backstack + permanentNavModel, - buildContext = buildContext, - plugins = plugins, - childKeepMode = childKeepMode, -) { - override fun onBuilt() { - super.onBuilt() - lifecycle.logLifecycle(this::class.java.simpleName) - whenChildAttached { _, child -> - // BackstackNode will be logged by their parent. - if (child !is BackstackNode<*>) { - child.lifecycle.logLifecycle(child::class.java.simpleName) - } - } - } -} diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt new file mode 100644 index 0000000000..f55706593e --- /dev/null +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/BaseFlowNode.kt @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.libraries.architecture + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.children.ChildEntry +import com.bumble.appyx.core.composable.Children +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.navigation.model.combined.plus +import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel +import com.bumble.appyx.core.navigation.transition.TransitionHandler +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.node.ParentNode +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.transitionhandler.rememberBackstackFader +import com.bumble.appyx.navmodel.backstack.transitionhandler.rememberBackstackSlider +import io.element.android.libraries.architecture.overlay.Overlay + +/** + * This class is a [ParentNode] that contains a [BackStack] and an [Overlay]. It is used to represent a flow in the app. + * Should be used instead of [ParentNode] in flow nodes. + */ +@Stable +abstract class BaseFlowNode( + val backstack: BackStack, + buildContext: BuildContext, + plugins: List, + val overlay: Overlay = Overlay(null), + val permanentNavModel: PermanentNavModel = PermanentNavModel(emptySet(), null), + childKeepMode: ChildEntry.KeepMode = ChildEntry.KeepMode.KEEP, +) : ParentNode( + navModel = overlay + backstack + permanentNavModel, + buildContext = buildContext, + plugins = plugins, + childKeepMode = childKeepMode, +) { + override fun onBuilt() { + super.onBuilt() + lifecycle.logLifecycle(this::class.java.simpleName) + whenChildAttached { _, child -> + // BackstackNode will be logged by their parent. + if (child !is BaseFlowNode<*>) { + child.lifecycle.logLifecycle(child::class.java.simpleName) + } + } + } +} + +@Composable +inline fun BaseFlowNode.BackstackView( + modifier: Modifier = Modifier, + transitionHandler: TransitionHandler = rememberBackstackSlider( + transitionSpec = { spring(stiffness = Spring.StiffnessMediumLow) }, + ), +) { + Children( + modifier = modifier, + navModel = backstack, + transitionHandler = transitionHandler, + ) +} + +@Composable +inline fun BaseFlowNode.OverlayView( + modifier: Modifier = Modifier, + transitionHandler: TransitionHandler = rememberBackstackFader(), +) { + Children( + modifier = modifier, + navModel = overlay, + transitionHandler = transitionHandler, + ) +} + +@Composable +inline fun BaseFlowNode.BackstackWithOverlayBox( + modifier: Modifier = Modifier, + content: @Composable BoxScope.() -> Unit = {}, +) { + Box(modifier = modifier) { + BackstackView() + OverlayView() + content() + } +}