From 13348bc52f74cea36705269d618763294941bdf4 Mon Sep 17 00:00:00 2001 From: Adrian Kuta Date: Sun, 15 Jun 2025 22:09:05 +0200 Subject: [PATCH] Refactor: Update package structure and implement bottom navigation This commit refactors the package structure for Gradle convention plugins and introduces bottom navigation to the application. Key changes: - Moved Gradle convention plugin files from `dev.adriankuta.partymania` to `dev.adriankuta.flights`. - Added `TopLevelDestination.kt` to define top-level navigation destinations with icons, titles, and routes. - Implemented `FlightsBottomBar` Composable in `FlightsApp.kt` to display a `NavigationBar` with items for each `TopLevelDestination`. - Updated `FlightsNavGraph.kt`: - Renamed from `FlightsNavGraph.kt` to `navigation/FlightsNavGraph.kt`. - Added `navigateToTopLevelDestination` extension function for `NavController` to handle navigation to top-level destinations with appropriate `NavOptions`. - Updated `HomeNavigation.kt`: - Added `navigateToHome` extension function for `NavController`. - Added `strings.xml` for `ui:home` module with `home_screen_title`. - Ensured Kotlin serialization plugin is correctly applied in `app/build.gradle.kts`. --- app/build.gradle.kts | 2 +- .../dev/adriankuta/flights/FlightsNavGraph.kt | 23 -------- .../flights/navigation/FlightsNavGraph.kt | 51 ++++++++++++++++++ .../flights/navigation/TopLevelDestination.kt | 28 ++++++++++ .../dev/adriankuta/flights/ui/FlightsApp.kt | 54 ++++++++++++++++++- .../ConfigureAndroidLint.kt | 0 .../ConfigureCompose.kt | 0 .../ConfigureDetekt.kt | 0 .../ConfigureFlavors.kt | 0 .../ConfigureGradleManagedDevices.kt | 0 .../{partymania => flights}/ConfigureHilt.kt | 0 .../ConfigureInstrumentation.kt | 0 .../ConfigureJacoco.kt | 0 .../ConfigureKotlinAndroid.kt | 0 .../ConfigureLibrary.kt | 0 .../{partymania => flights}/ConfigureSonar.kt | 0 .../ConfigureUnitTests.kt | 0 .../ui/home/navigation/HomeNavigation.kt | 8 +++ ui/home/src/main/res/values/strings.xml | 4 ++ 19 files changed, 144 insertions(+), 26 deletions(-) delete mode 100644 app/src/main/kotlin/dev/adriankuta/flights/FlightsNavGraph.kt create mode 100644 app/src/main/kotlin/dev/adriankuta/flights/navigation/FlightsNavGraph.kt create mode 100644 app/src/main/kotlin/dev/adriankuta/flights/navigation/TopLevelDestination.kt rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureAndroidLint.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureCompose.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureDetekt.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureFlavors.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureGradleManagedDevices.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureHilt.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureInstrumentation.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureJacoco.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureKotlinAndroid.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureLibrary.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureSonar.kt (100%) rename build-logic/convention/src/main/kotlin/dev/adriankuta/{partymania => flights}/ConfigureUnitTests.kt (100%) create mode 100644 ui/home/src/main/res/values/strings.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3ae9c0a..a660f9e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { - alias(libs.plugins.kotlin.serialization) alias(libs.plugins.flights.android.application.compose) alias(libs.plugins.flights.android.application.hilt) + alias(libs.plugins.kotlin.serialization) } android { diff --git a/app/src/main/kotlin/dev/adriankuta/flights/FlightsNavGraph.kt b/app/src/main/kotlin/dev/adriankuta/flights/FlightsNavGraph.kt deleted file mode 100644 index e6027eb..0000000 --- a/app/src/main/kotlin/dev/adriankuta/flights/FlightsNavGraph.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.adriankuta.flights - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.navigation.NavHostController -import androidx.navigation.compose.NavHost -import androidx.navigation.compose.rememberNavController -import dev.adriankuta.flights.ui.home.navigation.HomeRoute -import dev.adriankuta.flights.ui.home.navigation.homeScreen - -@Composable -fun FlightsNavGraph( - modifier: Modifier = Modifier, - navController: NavHostController = rememberNavController(), -) { - NavHost( - navController = navController, - startDestination = HomeRoute, - modifier = modifier, - ) { - homeScreen() - } -} diff --git a/app/src/main/kotlin/dev/adriankuta/flights/navigation/FlightsNavGraph.kt b/app/src/main/kotlin/dev/adriankuta/flights/navigation/FlightsNavGraph.kt new file mode 100644 index 0000000..15a9e9e --- /dev/null +++ b/app/src/main/kotlin/dev/adriankuta/flights/navigation/FlightsNavGraph.kt @@ -0,0 +1,51 @@ +package dev.adriankuta.flights.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.util.trace +import androidx.navigation.NavController +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navOptions +import dev.adriankuta.flights.ui.home.navigation.HomeRoute +import dev.adriankuta.flights.ui.home.navigation.homeScreen +import dev.adriankuta.flights.ui.home.navigation.navigateToHome + +@Composable +fun FlightsNavGraph( + modifier: Modifier = Modifier, + navController: NavHostController = rememberNavController(), +) { + NavHost( + navController = navController, + startDestination = HomeRoute, + modifier = modifier, + ) { + homeScreen() + } +} + +fun NavController.navigateToTopLevelDestination(topLevelDestination: TopLevelDestination) { + trace("Navigation: ${topLevelDestination.name}") { + val topLevelNavOptions = navOptions { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(graph.findStartDestination().id) { + saveState = true + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = true + } + + when (topLevelDestination) { + TopLevelDestination.HOME -> navigateToHome(topLevelNavOptions) + TopLevelDestination.STATIONS -> navigateToHome(topLevelNavOptions) + } + } +} diff --git a/app/src/main/kotlin/dev/adriankuta/flights/navigation/TopLevelDestination.kt b/app/src/main/kotlin/dev/adriankuta/flights/navigation/TopLevelDestination.kt new file mode 100644 index 0000000..84156d2 --- /dev/null +++ b/app/src/main/kotlin/dev/adriankuta/flights/navigation/TopLevelDestination.kt @@ -0,0 +1,28 @@ +package dev.adriankuta.flights.navigation + +import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Place +import androidx.compose.material.icons.outlined.Search +import androidx.compose.ui.graphics.vector.ImageVector +import dev.adriankuta.flights.ui.home.navigation.HomeRoute +import kotlin.reflect.KClass +import dev.adriankuta.flights.ui.home.R as homeR + +enum class TopLevelDestination( + val icon: ImageVector, + @StringRes val titleTextId: Int, + val route: KClass<*>, + val baseRoute: KClass<*> = route, +) { + HOME( + icon = Icons.Outlined.Search, + titleTextId = homeR.string.home_screen_title, + route = HomeRoute::class, + ), + STATIONS( + icon = Icons.Outlined.Place, + titleTextId = homeR.string.home_screen_title, + route = HomeRoute::class, + ), +} diff --git a/app/src/main/kotlin/dev/adriankuta/flights/ui/FlightsApp.kt b/app/src/main/kotlin/dev/adriankuta/flights/ui/FlightsApp.kt index da24fda..f149476 100644 --- a/app/src/main/kotlin/dev/adriankuta/flights/ui/FlightsApp.kt +++ b/app/src/main/kotlin/dev/adriankuta/flights/ui/FlightsApp.kt @@ -1,25 +1,75 @@ package dev.adriankuta.flights.ui import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarDefaults +import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import dev.adriankuta.flights.FlightsNavGraph +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import dev.adriankuta.flights.navigation.FlightsNavGraph +import dev.adriankuta.flights.navigation.TopLevelDestination +import dev.adriankuta.flights.navigation.navigateToTopLevelDestination import dev.adriankuta.flights.ui.designsystem.theme.Elevation @Composable fun FlightsApp( modifier: Modifier = Modifier, ) { + val navController = rememberNavController() + Surface( tonalElevation = Elevation.Surface, modifier = modifier, ) { Scaffold( snackbarHost = { InAppUpdates() }, + bottomBar = { + FlightsBottomBar( + navController = navController, + ) + }, ) { paddingValues -> - FlightsNavGraph(Modifier.padding(paddingValues)) + FlightsNavGraph( + navController = navController, + modifier = Modifier.padding(paddingValues), + ) + } + } +} + +@Composable +internal fun FlightsBottomBar( + navController: NavHostController = rememberNavController(), +) { + var selectedDestination by rememberSaveable { mutableIntStateOf(0) } + + NavigationBar(windowInsets = NavigationBarDefaults.windowInsets) { + TopLevelDestination.entries.forEachIndexed { index, destination -> + NavigationBarItem( + selected = selectedDestination == index, + onClick = { + selectedDestination = index + navController.navigateToTopLevelDestination(TopLevelDestination.HOME) + }, + icon = { + Icon( + destination.icon, + contentDescription = null, + ) + }, + label = { Text(stringResource(destination.titleTextId)) }, + ) } } } diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureAndroidLint.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureAndroidLint.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureAndroidLint.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureAndroidLint.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureCompose.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureCompose.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureCompose.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureCompose.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureDetekt.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureDetekt.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureDetekt.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureDetekt.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureFlavors.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureFlavors.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureFlavors.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureFlavors.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureGradleManagedDevices.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureGradleManagedDevices.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureGradleManagedDevices.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureGradleManagedDevices.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureHilt.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureHilt.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureHilt.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureHilt.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureInstrumentation.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureInstrumentation.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureInstrumentation.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureInstrumentation.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureJacoco.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureJacoco.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureJacoco.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureJacoco.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureKotlinAndroid.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureKotlinAndroid.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureKotlinAndroid.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureKotlinAndroid.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureLibrary.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureLibrary.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureLibrary.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureLibrary.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureSonar.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureSonar.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureSonar.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureSonar.kt diff --git a/build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureUnitTests.kt b/build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureUnitTests.kt similarity index 100% rename from build-logic/convention/src/main/kotlin/dev/adriankuta/partymania/ConfigureUnitTests.kt rename to build-logic/convention/src/main/kotlin/dev/adriankuta/flights/ConfigureUnitTests.kt diff --git a/ui/home/src/main/kotlin/dev/adriankuta/flights/ui/home/navigation/HomeNavigation.kt b/ui/home/src/main/kotlin/dev/adriankuta/flights/ui/home/navigation/HomeNavigation.kt index 013371e..84ce289 100644 --- a/ui/home/src/main/kotlin/dev/adriankuta/flights/ui/home/navigation/HomeNavigation.kt +++ b/ui/home/src/main/kotlin/dev/adriankuta/flights/ui/home/navigation/HomeNavigation.kt @@ -2,7 +2,9 @@ package dev.adriankuta.flights.ui.home.navigation +import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions import androidx.navigation.compose.composable import dev.adriankuta.flights.ui.home.HomeScreen import kotlinx.serialization.Serializable @@ -10,6 +12,12 @@ import kotlinx.serialization.Serializable @Serializable data object HomeRoute +fun NavController.navigateToHome( + navOptions: NavOptions, +) { + navigate(route = HomeRoute, navOptions = navOptions) +} + fun NavGraphBuilder.homeScreen() { composable { HomeScreen() diff --git a/ui/home/src/main/res/values/strings.xml b/ui/home/src/main/res/values/strings.xml new file mode 100644 index 0000000..2fc47e3 --- /dev/null +++ b/ui/home/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Search Flight + \ No newline at end of file