diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListScreen.kt index 23fc80bddf21..4c647f02f7fa 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListScreen.kt @@ -1,14 +1,13 @@ package com.woocommerce.android.ui.bookings.filter import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.ContentTransform +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally -import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -19,11 +18,15 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import com.woocommerce.android.R import com.woocommerce.android.ui.compose.component.Toolbar import com.woocommerce.android.ui.compose.component.WCColoredButton @@ -32,10 +35,6 @@ import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground @Composable fun BookingFilterListScreen(state: BookingFilterListUiState) { - BackHandler { - state.onClose() - } - Scaffold( topBar = { Column { @@ -66,62 +65,94 @@ fun BookingFilterListScreen(state: BookingFilterListUiState) { }, containerColor = MaterialTheme.colorScheme.surface, ) { innerPadding -> - AnimatedContent( - targetState = state.currentPage, - transitionSpec = { - if (targetState is BookingFilterPage.List) { - slideOut() - } else { - slideIn() - } - }, - label = "BookingFiltersAnimatedContent", + FiltersNavHost( + state = state, modifier = Modifier .fillMaxSize() .padding(innerPadding) - ) { page -> - when (page) { - is BookingFilterPage.List -> { - BookingFilterRootPage(state.items) - } + ) - BookingFilterPage.AttendanceStatus, - BookingFilterPage.BookingType, - BookingFilterPage.Customer, - BookingFilterPage.Location, - BookingFilterPage.PaymentStatus, - BookingFilterPage.ServiceEvent, - BookingFilterPage.TeamMember, - is BookingFilterPage.DateTime -> { - DateTimeFilterPicker() - } + // The navigation is driven by the state, so we handle back navigation by calling onClose + // We need to ensure that this called after NavHost to make sure we receive back events + BackHandler { + state.onClose() + } + } +} + +@Composable +private fun FiltersNavHost( + state: BookingFilterListUiState, + modifier: Modifier +) { + val navController = rememberNavController() + + LaunchedEffect(state.currentPage) { + if (state.currentPage != BookingFilterPage.List) { + navController.navigate(state.currentPage.route) { + popUpTo(BookingFilterPage.List.route) } + } else { + navController.popBackStack(BookingFilterPage.List.route, false) + } + } + + NavHost( + navController = navController, + startDestination = BookingFilterPage.List.route, + enterTransition = { slideIn(popNavigation = true) }, + exitTransition = { slideOut(popNavigation = true) }, + popEnterTransition = { slideIn(popNavigation = false) }, + popExitTransition = { slideOut(popNavigation = false) }, + modifier = modifier + ) { + composable(BookingFilterPage.List.route) { + BookingFilterRootPage(state.items) + } + composable(BookingFilterPage.DateTime.route) { + DateTimeFilterPicker() + } + composable(BookingFilterPage.TeamMember.route) { + TODO() + } + composable(BookingFilterPage.AttendanceStatus.route) { + TODO() + } + composable(BookingFilterPage.PaymentStatus.route) { + TODO() + } + composable(BookingFilterPage.BookingType.route) { + TODO() + } + composable(BookingFilterPage.Customer.route) { + TODO() + } + composable(BookingFilterPage.ServiceEvent.route) { + TODO() + } + composable(BookingFilterPage.Location.route) { + TODO() } } } -private const val TRANSITION_DURATION = 250 +private val BookingFilterPage.route: String + get() = name -private fun slideIn(duration: Int = TRANSITION_DURATION): ContentTransform { - return ( - slideInHorizontally(animationSpec = tween(durationMillis = duration)) { fullWidth -> fullWidth } + - fadeIn(animationSpec = tween(durationMillis = duration)) - ) togetherWith ( - slideOutHorizontally(animationSpec = tween(durationMillis = duration)) { fullWidth -> -fullWidth } + - fadeOut(animationSpec = tween(durationMillis = duration)) - ) +private fun slideIn(popNavigation: Boolean): EnterTransition { + return slideInHorizontally(animationSpec = tween(durationMillis = TRANSITION_DURATION)) { fullWidth -> + if (popNavigation) fullWidth else -fullWidth + } + fadeIn(animationSpec = tween(durationMillis = TRANSITION_DURATION)) } -private fun slideOut(duration: Int = TRANSITION_DURATION): ContentTransform { - return ( - slideInHorizontally(animationSpec = tween(durationMillis = duration)) { fullWidth -> -fullWidth } + - fadeIn(animationSpec = tween(durationMillis = duration)) - ) togetherWith ( - slideOutHorizontally(animationSpec = tween(durationMillis = duration)) { fullWidth -> fullWidth } + - fadeOut(animationSpec = tween(durationMillis = duration)) - ) +private fun slideOut(popNavigation: Boolean): ExitTransition { + return slideOutHorizontally(animationSpec = tween(durationMillis = TRANSITION_DURATION)) { fullWidth -> + if (popNavigation) -fullWidth else fullWidth + } + fadeOut(animationSpec = tween(durationMillis = TRANSITION_DURATION)) } +private const val TRANSITION_DURATION = 250 + @LightDarkThemePreviews @Composable private fun BookingFilterListScreenPreview() { diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListUiState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListUiState.kt index 81629015432a..8d72da0de22d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListUiState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/filter/BookingFilterListUiState.kt @@ -6,16 +6,16 @@ import com.woocommerce.android.R import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingFilters import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingsFilterOption -sealed interface BookingFilterPage { - data object List : BookingFilterPage - data object DateTime : BookingFilterPage - data object TeamMember : BookingFilterPage - data object AttendanceStatus : BookingFilterPage - data object PaymentStatus : BookingFilterPage - data object BookingType : BookingFilterPage - data object Customer : BookingFilterPage - data object ServiceEvent : BookingFilterPage - data object Location : BookingFilterPage +enum class BookingFilterPage { + List, + DateTime, + TeamMember, + AttendanceStatus, + PaymentStatus, + BookingType, + Customer, + ServiceEvent, + Location, } data class BookingFilterListUiState( @@ -37,7 +37,7 @@ data class BookingFilterListUiState( @DrawableRes val navigationIcon: Int = when (currentPage) { - is BookingFilterPage.List -> R.drawable.ic_gridicons_cross_24dp + BookingFilterPage.List -> R.drawable.ic_gridicons_cross_24dp else -> R.drawable.ic_back_24dp }