diff --git a/app/src/main/kotlin/io/element/android/x/MainActivity.kt b/app/src/main/kotlin/io/element/android/x/MainActivity.kt index 364ab6396d..9a3f7951e8 100644 --- a/app/src/main/kotlin/io/element/android/x/MainActivity.kt +++ b/app/src/main/kotlin/io/element/android/x/MainActivity.kt @@ -48,7 +48,7 @@ class MainActivity : NodeComponentActivity() { buildContext = it, appComponentOwner = applicationContext as DaggerComponentOwner, authenticationService = appBindings.authenticationService(), - rootPresenter = appBindings.rootPresenter() + presenter = appBindings.rootPresenter() ) } } diff --git a/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt index 774b42b220..b2e2aca077 100644 --- a/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt @@ -32,16 +32,17 @@ import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.node.node import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push +import io.element.android.features.preferences.PreferencesFlowNode +import io.element.android.features.roomlist.RoomListNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.DaggerComponentOwner -import io.element.android.x.di.SessionComponent -import io.element.android.features.preferences.PreferencesFlowNode -import io.element.android.features.roomlist.RoomListNode import io.element.android.libraries.matrix.MatrixClient import io.element.android.libraries.matrix.core.RoomId import io.element.android.libraries.matrix.core.SessionId import io.element.android.libraries.matrix.ui.di.MatrixUIBindings +import io.element.android.x.di.SessionComponent import kotlinx.parcelize.Parcelize class LoggedInFlowNode( @@ -124,6 +125,11 @@ class LoggedInFlowNode( @Composable override fun View(modifier: Modifier) { - Children(navModel = backstack) + Children( + navModel = backstack, + modifier = modifier, + // Animate navigation to settings and to a room + transitionHandler = rememberDefaultTransitionHandler(), + ) } } diff --git a/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt index 91a85c1e85..b9e38d1063 100644 --- a/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/NotLoggedInFlowNode.kt @@ -26,9 +26,10 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.core.node.node import com.bumble.appyx.navmodel.backstack.BackStack -import com.bumble.appyx.navmodel.backstack.operation.replace +import com.bumble.appyx.navmodel.backstack.operation.push import io.element.android.features.login.LoginFlowNode import io.element.android.features.onboarding.OnBoardingScreen +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import kotlinx.parcelize.Parcelize import timber.log.Timber @@ -62,7 +63,7 @@ class NotLoggedInFlowNode( return when (navTarget) { NavTarget.OnBoarding -> node(buildContext) { OnBoardingScreen( - onSignIn = { backstack.replace(NavTarget.LoginFlow) } + onSignIn = { backstack.push(NavTarget.LoginFlow) } ) } NavTarget.LoginFlow -> LoginFlowNode(buildContext) @@ -71,6 +72,11 @@ class NotLoggedInFlowNode( @Composable override fun View(modifier: Modifier) { - Children(navModel = backstack) + Children( + navModel = backstack, + modifier = modifier, + // Animate navigation to login screen + transitionHandler = rememberDefaultTransitionHandler(), + ) } } diff --git a/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt index 0048b143cf..bae60841d6 100644 --- a/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/RoomFlowNode.kt @@ -25,12 +25,12 @@ import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.navmodel.backstack.BackStack +import io.element.android.features.messages.MessagesNode import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.DaggerComponentOwner -import io.element.android.x.di.RoomComponent -import io.element.android.features.messages.MessagesNode import io.element.android.libraries.matrix.room.MatrixRoom +import io.element.android.x.di.RoomComponent import kotlinx.parcelize.Parcelize import timber.log.Timber @@ -70,6 +70,9 @@ class RoomFlowNode( @Composable override fun View(modifier: Modifier) { - Children(navModel = backstack) + Children( + navModel = backstack, + modifier = modifier, + ) } } diff --git a/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt b/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt index cf7346f801..d82ac55e7f 100644 --- a/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt +++ b/app/src/main/kotlin/io/element/android/x/node/RootFlowNode.kt @@ -36,10 +36,11 @@ import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.newRoot import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push +import io.element.android.features.rageshake.bugreport.BugReportNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.presenterConnector import io.element.android.libraries.di.DaggerComponentOwner -import io.element.android.features.rageshake.bugreport.BugReportNode import io.element.android.libraries.matrix.MatrixClient import io.element.android.libraries.matrix.auth.MatrixAuthenticationService import io.element.android.libraries.matrix.core.SessionId @@ -60,7 +61,7 @@ class RootFlowNode( ), private val appComponentOwner: DaggerComponentOwner, private val authenticationService: MatrixAuthenticationService, - rootPresenter: RootPresenter + presenter: RootPresenter ) : ParentNode( navModel = backstack, @@ -70,7 +71,7 @@ class RootFlowNode( DaggerComponentOwner by appComponentOwner { private val matrixClientsHolder = ConcurrentHashMap() - private val presenterConnector = presenterConnector(rootPresenter) + private val presenterConnector = presenterConnector(presenter) override fun onBuilt() { super.onBuilt() @@ -107,9 +108,14 @@ class RootFlowNode( val state by presenterConnector.stateFlow.collectAsState() RootView( state = state, + modifier = modifier, onOpenBugReport = this::onOpenBugReport, ) { - Children(navModel = backstack) + Children( + navModel = backstack, + // Animate opening the bug report screen + transitionHandler = rememberDefaultTransitionHandler(), + ) } } diff --git a/features/login/src/main/kotlin/io/element/android/features/login/LoginFlowNode.kt b/features/login/src/main/kotlin/io/element/android/features/login/LoginFlowNode.kt index ae0f6268a0..641435642d 100644 --- a/features/login/src/main/kotlin/io/element/android/features/login/LoginFlowNode.kt +++ b/features/login/src/main/kotlin/io/element/android/features/login/LoginFlowNode.kt @@ -25,9 +25,10 @@ import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push -import io.element.android.libraries.architecture.createNode import io.element.android.features.login.changeserver.ChangeServerNode import io.element.android.features.login.root.LoginRootNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler +import io.element.android.libraries.architecture.createNode import kotlinx.parcelize.Parcelize class LoginFlowNode( @@ -64,6 +65,11 @@ class LoginFlowNode( @Composable override fun View(modifier: Modifier) { - Children(navModel = backstack) + Children( + navModel = backstack, + modifier = modifier, + // Animate transition to change server screen + transitionHandler = rememberDefaultTransitionHandler(), + ) } } diff --git a/features/login/src/main/kotlin/io/element/android/features/login/changeserver/ChangeServerNode.kt b/features/login/src/main/kotlin/io/element/android/features/login/changeserver/ChangeServerNode.kt index 4cec3ad0be..b0c8b96ed5 100644 --- a/features/login/src/main/kotlin/io/element/android/features/login/changeserver/ChangeServerNode.kt +++ b/features/login/src/main/kotlin/io/element/android/features/login/changeserver/ChangeServerNode.kt @@ -33,7 +33,7 @@ import io.element.android.libraries.di.AppScope class ChangeServerNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: ChangeServerPresenter, + presenter: ChangeServerPresenter, ) : Node(buildContext, plugins = plugins) { private val presenterConnector = presenterConnector(presenter) @@ -47,6 +47,7 @@ class ChangeServerNode @AssistedInject constructor( val state by presenterConnector.stateFlow.collectAsState() ChangeServerView( state = state, + modifier = modifier, onChangeServerSuccess = this::onSuccess, ) } diff --git a/features/login/src/main/kotlin/io/element/android/features/login/root/LoginRootNode.kt b/features/login/src/main/kotlin/io/element/android/features/login/root/LoginRootNode.kt index 6067171c46..695a4eccb1 100644 --- a/features/login/src/main/kotlin/io/element/android/features/login/root/LoginRootNode.kt +++ b/features/login/src/main/kotlin/io/element/android/features/login/root/LoginRootNode.kt @@ -36,7 +36,7 @@ import io.element.android.libraries.di.AppScope class LoginRootNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: LoginRootPresenter, + presenter: LoginRootPresenter, ) : Node(buildContext, plugins = plugins) { private val presenterConnector = presenterConnector(presenter) @@ -60,6 +60,7 @@ class LoginRootNode @AssistedInject constructor( } LoginRootScreen( state = state, + modifier = modifier, onChangeServer = this::onChangeHomeServer, ) } diff --git a/features/preferences/src/main/kotlin/io/element/android/features/preferences/PreferencesFlowNode.kt b/features/preferences/src/main/kotlin/io/element/android/features/preferences/PreferencesFlowNode.kt index a3e9e4e283..5407072398 100644 --- a/features/preferences/src/main/kotlin/io/element/android/features/preferences/PreferencesFlowNode.kt +++ b/features/preferences/src/main/kotlin/io/element/android/features/preferences/PreferencesFlowNode.kt @@ -24,8 +24,9 @@ import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.node.ParentNode import com.bumble.appyx.navmodel.backstack.BackStack -import io.element.android.libraries.architecture.createNode import io.element.android.features.preferences.root.PreferencesRootNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler +import io.element.android.libraries.architecture.createNode import kotlinx.parcelize.Parcelize class PreferencesFlowNode( @@ -59,6 +60,10 @@ class PreferencesFlowNode( @Composable override fun View(modifier: Modifier) { - Children(navModel = backstack) + Children( + navModel = backstack, + modifier = modifier, + transitionHandler = rememberDefaultTransitionHandler() + ) } } diff --git a/features/preferences/src/main/kotlin/io/element/android/features/preferences/root/PreferencesRootNode.kt b/features/preferences/src/main/kotlin/io/element/android/features/preferences/root/PreferencesRootNode.kt index b1ef84646b..92688e5b32 100644 --- a/features/preferences/src/main/kotlin/io/element/android/features/preferences/root/PreferencesRootNode.kt +++ b/features/preferences/src/main/kotlin/io/element/android/features/preferences/root/PreferencesRootNode.kt @@ -34,7 +34,7 @@ import io.element.android.libraries.di.SessionScope class PreferencesRootNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: PreferencesRootPresenter, + presenter: PreferencesRootPresenter, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { @@ -52,6 +52,7 @@ class PreferencesRootNode @AssistedInject constructor( val state by presenterConnector.stateFlow.collectAsState() PreferencesRootView( state = state, + modifier = modifier, onBackPressed = this::navigateUp, onOpenRageShake = this::onOpenBugReport ) diff --git a/features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListNode.kt b/features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListNode.kt index 4e153a2328..f492e09871 100644 --- a/features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListNode.kt +++ b/features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListNode.kt @@ -58,6 +58,7 @@ class RoomListNode @AssistedInject constructor( val state by connector.stateFlow.collectAsState() RoomListView( state = state, + modifier = modifier, onRoomClicked = this::onRoomClicked, onOpenSettings = this::onOpenSettings ) diff --git a/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/animation/ScreenTransition.kt b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/animation/ScreenTransition.kt new file mode 100644 index 0000000000..faac896b85 --- /dev/null +++ b/libraries/architecture/src/main/kotlin/io/element/android/libraries/architecture/animation/ScreenTransition.kt @@ -0,0 +1,31 @@ +/* + * 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.animation + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.runtime.Composable +import com.bumble.appyx.core.navigation.transition.ModifierTransitionHandler +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.transitionhandler.rememberBackstackSlider + +@Composable +fun rememberDefaultTransitionHandler(): ModifierTransitionHandler { + return rememberBackstackSlider( + transitionSpec = { spring(stiffness = Spring.StiffnessMediumLow) }, + ) +}