Skip to content

Commit

Permalink
Adaptive navigation types. (#181)
Browse files Browse the repository at this point in the history
Fix #179.
  • Loading branch information
AdamMc331 committed Mar 2, 2023
1 parent a2767cf commit 6fd6376
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 69 deletions.
11 changes: 11 additions & 0 deletions StreamHistory.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The following is a record of all TOA streams in chronological order.
* [Stream Thirty Four - MainActivity UI Tests](#stream-thirty-four---mainactivity-ui-tests)
* [Stream Thirty Five - Bottom Bar For Settings](#stream-thirty-five---user-settings)
* [Stream Thirty Six - Settings Implementation](#stream-thirty-six---user-settings-continued)
* [Stream Thirty Seven - Adaptive Navigation Types](#stream-thirty-seven---adaptive-navigation-types)
</details>

<details>
Expand Down Expand Up @@ -587,3 +588,13 @@ PRs:
YouTube:
* Coming Soon

## Stream Thirty Seven - Adaptive Navigation Types

In this stream, we implemented the material 3 window size class dependency & changed our navigation
type based on screen width.

PRs:
* https://github.com/AdamMc331/TOA/pull/181

YouTube:
* Coming Soon
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ dependencies {
// For the known issue: https://developer.android.com/jetpack/androidx/releases/compose-material3#1.1.0-alpha04
implementation "androidx.compose.foundation:foundation:1.4.0-alpha03"
implementation "androidx.compose.material3:material3:1.1.0-alpha04"
implementation "androidx.compose.material3:material3-window-size-class:1.1.0-alpha04"
implementation "io.github.raamcosta.compose-destinations:animations-core:$rootProject.ext.versions.composeDestinations"
implementation "androidx.navigation:navigation-compose:$rootProject.ext.versions.composeNavigation"
implementation "com.google.accompanist:accompanist-navigation-animation:$rootProject.ext.versions.accompanist"
Expand Down
78 changes: 50 additions & 28 deletions app/src/main/java/com/adammcneilly/toa/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentActivity
import com.adammcneilly.toa.core.ui.WindowSize
import com.adammcneilly.toa.core.ui.components.navigation.NavigationTab
import com.adammcneilly.toa.core.ui.components.navigation.TOABottomNavigation
import com.adammcneilly.toa.core.ui.components.navigation.NavigationType
import com.adammcneilly.toa.core.ui.components.navigation.TOANavigationContainer
import com.adammcneilly.toa.core.ui.rememberWindowSizeClass
import com.adammcneilly.toa.core.ui.theme.TOATheme
import com.adammcneilly.toa.destinations.LoginScreenDestination
Expand Down Expand Up @@ -82,6 +84,7 @@ class MainActivity : FragmentActivity() {
}
}

@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@Composable
private fun TOANavHost(
startRoute: Route,
Expand All @@ -100,32 +103,41 @@ class MainActivity : FragmentActivity() {

val navController = navigationEngine.rememberNavController()

Column {
DestinationsNavHost(
startRoute = startRoute,
navGraph = NavGraphs.root,
engine = navigationEngine,
navController = navController,
manualComposableCallsBuilder = {
composable(TaskListScreenDestination) {
TaskListScreen(
navigator = destinationsNavigator,
windowSize = windowSize,
)
}
},
modifier = Modifier
.weight(1F),
)
val windowSizeClass = calculateWindowSizeClass(activity = this)

TOABottomNavigation(
navHostController = navController,
tabs = listOf(
NavigationTab.Home,
NavigationTab.Settings,
),
)
}
val navigationType = getNavigationType(windowSizeClass.widthSizeClass)

val navigationTabs = listOf(
NavigationTab.Home,
NavigationTab.Settings,
)

TOAAppScaffold(
navigationType = navigationType,
navigationContent = {
TOANavigationContainer(
navHostController = navController,
tabs = navigationTabs,
navigationType = navigationType,
)
},
appContent = {
DestinationsNavHost(
startRoute = startRoute,
navGraph = NavGraphs.root,
engine = navigationEngine,
navController = navController,
manualComposableCallsBuilder = {
composable(TaskListScreenDestination) {
TaskListScreen(
navigator = destinationsNavigator,
windowSize = windowSize,
)
}
},
)
}
)
}

private fun keepSplashScreenVisibleWhileInitializing() {
Expand Down Expand Up @@ -162,4 +174,14 @@ class MainActivity : FragmentActivity() {
)
}
}

private fun getNavigationType(
widthSizeClass: WindowWidthSizeClass,
): NavigationType {
return when (widthSizeClass) {
WindowWidthSizeClass.Expanded -> NavigationType.PERMANENT_NAVIGATION_DRAWER
WindowWidthSizeClass.Medium -> NavigationType.NAVIGATION_RAIL
else -> NavigationType.BOTTOM_NAVIGATION
}
}
}
86 changes: 86 additions & 0 deletions app/src/main/java/com/adammcneilly/toa/TOAAppScaffold.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.adammcneilly.toa

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.PermanentNavigationDrawer
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.adammcneilly.toa.core.ui.components.navigation.NavigationType

@Composable
fun TOAAppScaffold(
navigationType: NavigationType,
navigationContent: @Composable () -> Unit,
appContent: @Composable () -> Unit,
) {
when (navigationType) {
NavigationType.BOTTOM_NAVIGATION -> {
VerticalAppScaffold(
navigationContent = navigationContent,
appContent = appContent,
)
}
NavigationType.NAVIGATION_RAIL -> {
HorizontalAppScaffold(
navigationContent = navigationContent,
appContent = appContent,
)
}
NavigationType.PERMANENT_NAVIGATION_DRAWER -> {
PermanentNavigationScaffold(
navigationContent = navigationContent,
appContent = appContent,
)
}
}
}

@Composable
private fun HorizontalAppScaffold(
navigationContent: @Composable () -> Unit,
appContent: @Composable () -> Unit,
) {
Row {
navigationContent()

Box(
modifier = Modifier
.weight(1F),
) {
appContent()
}
}
}

@Composable
private fun VerticalAppScaffold(
navigationContent: @Composable () -> Unit,
appContent: @Composable () -> Unit,
) {
Column {
Box(
modifier = Modifier
.weight(1F),
) {
appContent()
}

navigationContent()
}
}

@Composable
private fun PermanentNavigationScaffold(
navigationContent: @Composable () -> Unit,
appContent: @Composable () -> Unit,
) {
PermanentNavigationDrawer(
drawerContent = {
navigationContent()
},
content = {
appContent()
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.adammcneilly.toa.ExcludeFromJacocoGeneratedReport
import com.adammcneilly.toa.core.ui.theme.TOATheme
import com.adammcneilly.toa.toEpochMillisUTC
import java.time.LocalDate
Expand Down Expand Up @@ -95,6 +96,7 @@ private fun DatePickerButtonRow(
uiMode = Configuration.UI_MODE_NIGHT_NO,
)
@Composable
@ExcludeFromJacocoGeneratedReport
private fun TOADatePickerDialogPreview() {
TOATheme {
TOADatePickerDialog(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.adammcneilly.toa.core.ui.components.navigation

enum class NavigationType {
BOTTOM_NAVIGATION,
NAVIGATION_RAIL,
PERMANENT_NAVIGATION_DRAWER,
}
Original file line number Diff line number Diff line change
@@ -1,60 +1,39 @@
package com.adammcneilly.toa.core.ui.components.navigation

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavHostController
import com.ramcosta.composedestinations.utils.currentDestinationAsState

@Composable
fun TOABottomNavigation(
navHostController: NavHostController,
tabs: List<NavigationTab>,
navigationConfig: TOANavigationConfig,
modifier: Modifier = Modifier,
) {
val currentRoute = navHostController.currentDestinationAsState().value?.route

val shouldShowBottomBar = tabs.any { tab ->
tab.screenRoute == currentRoute
}

AnimatedVisibility(
visible = shouldShowBottomBar,
NavigationBar(
modifier = modifier,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(),
) {
NavigationBar {
tabs.forEach { tab ->
NavigationBarItem(
selected = tab.screenRoute == currentRoute,
onClick = {
if (tab.screenRoute != currentRoute) {
navHostController.navigate(tab.screenRoute)
}
},
icon = {
Icon(
imageVector = tab.icon,
contentDescription = stringResource(id = tab.labelTextRes),
)
},
label = {
Text(
text = stringResource(id = tab.labelTextRes),
)
},
)
}
navigationConfig.tabs.forEach { tab ->
NavigationBarItem(
selected = tab == navigationConfig.selectedTab,
onClick = {
navigationConfig.onTabClicked.invoke(tab)
},
icon = {
Icon(
imageVector = tab.icon,
contentDescription = stringResource(id = tab.labelTextRes),
)
},
label = {
Text(
text = stringResource(id = tab.labelTextRes),
)
},
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.adammcneilly.toa.core.ui.components.navigation

/**
* All forms of navigation within the TOA app share the same
* core functionality of showing some [NavigationTab] entities and
* handling their click events.
*/
data class TOANavigationConfig(
val tabs: List<NavigationTab>,
val selectedTab: NavigationTab?,
val onTabClicked: (NavigationTab) -> Unit,
)
Loading

0 comments on commit 6fd6376

Please sign in to comment.