mirror of
https://github.com/AdrianKuta/android-challange-adrian-kuta.git
synced 2025-07-01 14:58:03 +02:00
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`.
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin.serialization)
|
|
||||||
alias(libs.plugins.flights.android.application.compose)
|
alias(libs.plugins.flights.android.application.compose)
|
||||||
alias(libs.plugins.flights.android.application.hilt)
|
alias(libs.plugins.flights.android.application.hilt)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
|
),
|
||||||
|
}
|
@ -1,25 +1,75 @@
|
|||||||
package dev.adriankuta.flights.ui
|
package dev.adriankuta.flights.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
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.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
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 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
|
import dev.adriankuta.flights.ui.designsystem.theme.Elevation
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FlightsApp(
|
fun FlightsApp(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
tonalElevation = Elevation.Surface,
|
tonalElevation = Elevation.Surface,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
snackbarHost = { InAppUpdates() },
|
snackbarHost = { InAppUpdates() },
|
||||||
|
bottomBar = {
|
||||||
|
FlightsBottomBar(
|
||||||
|
navController = navController,
|
||||||
|
)
|
||||||
|
},
|
||||||
) { paddingValues ->
|
) { 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)) },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
package dev.adriankuta.flights.ui.home.navigation
|
package dev.adriankuta.flights.ui.home.navigation
|
||||||
|
|
||||||
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import dev.adriankuta.flights.ui.home.HomeScreen
|
import dev.adriankuta.flights.ui.home.HomeScreen
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@ -10,6 +12,12 @@ import kotlinx.serialization.Serializable
|
|||||||
@Serializable
|
@Serializable
|
||||||
data object HomeRoute
|
data object HomeRoute
|
||||||
|
|
||||||
|
fun NavController.navigateToHome(
|
||||||
|
navOptions: NavOptions,
|
||||||
|
) {
|
||||||
|
navigate(route = HomeRoute, navOptions = navOptions)
|
||||||
|
}
|
||||||
|
|
||||||
fun NavGraphBuilder.homeScreen() {
|
fun NavGraphBuilder.homeScreen() {
|
||||||
composable<HomeRoute> {
|
composable<HomeRoute> {
|
||||||
HomeScreen()
|
HomeScreen()
|
||||||
|
4
ui/home/src/main/res/values/strings.xml
Normal file
4
ui/home/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="home_screen_title">Search Flight</string>
|
||||||
|
</resources>
|
Reference in New Issue
Block a user