Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[do not merge] Update navigation usage #95

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
.externalNativeBuild
.cxx
local.properties
.kotlin
20 changes: 6 additions & 14 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@
* limitations under the License.
*/

@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.baselineprofile)
alias(libs.plugins.compose)
alias(libs.plugins.hilt)
alias(libs.plugins.kotlinAndroid)
alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.ksp)
}

kotlin {
jvmToolchain(17)
compilerOptions {
freeCompilerArgs = listOf("-Xcontext-receivers")
}
}

android {
Expand All @@ -47,20 +51,9 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = listOf("-Xcontext-receivers")
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
Expand All @@ -85,7 +78,6 @@ dependencies {
val composeBom = platform(libs.compose.bom)
implementation(composeBom)
androidTestImplementation(composeBom)
implementation(libs.compose.foundation)
implementation(libs.compose.ui)
implementation(libs.compose.ui.graphics)
implementation(libs.compose.ui.text.google.fonts)
Expand All @@ -99,14 +91,14 @@ dependencies {

implementation(libs.activity.compose)
implementation(libs.navigation.compose)
implementation(libs.kotlinx.serialization.json)

implementation(libs.accompanist.painter)
implementation(libs.accompanist.permissions)

implementation(libs.graphics.shapes)

implementation(libs.lifecycle.ktx)
implementation(libs.lifecycle.compose)
implementation(libs.lifecycle.runtime.compose)

ksp(libs.room.compiler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import android.os.Bundle
import android.view.WindowInsetsController
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
Expand All @@ -36,7 +35,6 @@ class MainActivity : ComponentActivity() {
installSplashScreen()
super.onCreate(savedInstanceState)
setContent {

// setSystemBarAppearance can be removed after calling enableEdgeToEdge()
setSystemBarAppearance(isSystemInDarkTheme())

Expand All @@ -55,16 +53,17 @@ class MainActivity : ComponentActivity() {
return ShortcutParams(shortcutId, text)
}

private fun setSystemBarAppearance(isSystemInDarkTheme : Boolean) {
private fun setSystemBarAppearance(isSystemInDarkTheme: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (isSystemInDarkTheme) {
window?.insetsController?.setSystemBarsAppearance(
0, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
0,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
)
} else {
window?.insetsController?.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ import android.app.Activity
import android.content.Intent
import android.content.pm.ActivityInfo
import android.os.Bundle
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,75 +28,90 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.adaptive.navigationsuite.ExperimentalMaterial3AdaptiveNavigationSuiteApi
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.google.android.samples.socialite.R
import com.google.android.samples.socialite.ui.AnimationConstants
import com.google.android.samples.socialite.ui.home.timeline.Timeline
import kotlinx.serialization.Serializable

@OptIn(ExperimentalMaterial3AdaptiveNavigationSuiteApi::class)
@Composable
fun Home(
onChatClicked: (chatId: Long) -> Unit,
modifier: Modifier = Modifier,
) {
var currentDestination by rememberSaveable { mutableStateOf(Destination.Chats) }
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = Destination.fromNavBackStackEntry(navBackStackEntry)

NavigationSuiteScaffold(
navigationSuiteItems = {
for (destination in Destination.entries) {
val selected = currentDestination.route == destination.route
Destination.entries.forEach {
val isSelected = it == currentDestination
item(
selected = selected,
onClick = { currentDestination = destination },
selected = isSelected,
onClick = {
if (!isSelected) {
navController.navigate(it.route) {
popUpTo(navController.graph.findStartDestination().id)
launchSingleTop = true
}
}
},
icon = {
Icon(
imageVector = destination.imageVector,
contentDescription = stringResource(destination.label),
imageVector = it.imageVector,
contentDescription = stringResource(it.label),
)
},
label = {
Text(text = stringResource(destination.label))
Text(text = stringResource(it.label))
},
alwaysShowLabel = false,
)
}
},
) { HomeContent(currentDestination, modifier, onChatClicked) }
) {
HomeContent(navController, currentDestination, modifier, onChatClicked)
}
}

@Composable
private fun HomeContent(
navController: NavHostController,
currentDestination: Destination,
modifier: Modifier,
onChatClicked: (chatId: Long) -> Unit,
) {
Scaffold(
modifier = modifier,
topBar = { HomeAppBar(title = stringResource(currentDestination.label)) },
topBar = {
HomeAppBar(title = stringResource(currentDestination.label))
},
) { innerPadding ->
val navController = rememberNavController()
HomeBackground(modifier = Modifier.fillMaxSize())
NavHost(
navController = navController,
startDestination = currentDestination.route,
startDestination = Destination.START_DESTINATION.route,
modifier = modifier,
) {
composable(
route = Destination.Timeline.route,
composable<Route.TimelineRoute>(
enterTransition = { AnimationConstants.enterTransition },
exitTransition = { AnimationConstants.exitTransition },
) {
Expand All @@ -105,8 +120,7 @@ private fun HomeContent(
modifier = modifier,
)
}
composable(
route = Destination.Chats.route,
composable<Route.ChatsRoute>(
enterTransition = { AnimationConstants.enterTransition },
exitTransition = { AnimationConstants.exitTransition },
) {
Expand All @@ -119,8 +133,7 @@ private fun HomeContent(
modifier = modifier,
)
}
composable(
route = Destination.Settings.route,
composable<Route.SettingsRoute>(
enterTransition = { AnimationConstants.enterTransition },
exitTransition = { AnimationConstants.exitTransition },
) {
Expand Down Expand Up @@ -148,24 +161,48 @@ fun HomeAppBar(
)
}

sealed interface Route {
@Serializable
data object TimelineRoute : Route

@Serializable
data object ChatsRoute : Route

@Serializable
data object SettingsRoute : Route
}

private enum class Destination(
val route: String,
val route: Route,
@StringRes val label: Int,
val imageVector: ImageVector,
) {
Timeline(
route = "timeline",
route = Route.TimelineRoute,
label = R.string.timeline,
imageVector = Icons.Outlined.VideoLibrary,
),
Chats(
route = "chats",
route = Route.ChatsRoute,
label = R.string.chats,
imageVector = Icons.Outlined.ChatBubbleOutline,
),
Settings(
route = "settings",
route = Route.SettingsRoute,
label = R.string.settings,
imageVector = Icons.Outlined.Settings,
),
;

companion object {
val START_DESTINATION = Chats

fun fromNavBackStackEntry(nbse: NavBackStackEntry?): Destination {
return entries.find { dest ->
nbse?.destination?.hierarchy?.any {
it.hasRoute(dest.route::class)
} == true
} ?: START_DESTINATION
}
}
}
6 changes: 4 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.androidTest) apply false
alias(libs.plugins.baselineprofile) apply false
alias(libs.plugins.kotlinAndroid) apply false
alias(libs.plugins.spotless) apply false
alias(libs.plugins.compose) apply false
alias(libs.plugins.hilt) apply false
alias(libs.plugins.kotlinAndroid) apply false
alias(libs.plugins.kotlinSerialization) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.spotless) apply false
}

subprojects {
Expand Down
Loading
Loading