From ba24685128dc80282f767280bd0fd2fb57dc81e5 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Wed, 10 Sep 2025 17:07:03 -0700 Subject: [PATCH 1/2] Add collapsable top bar --- .../com/android/ai/catalog/ui/CatalogApp.kt | 52 +++++++++++++++++-- .../app/src/main/res/values/strings.xml | 1 + 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt b/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt index 9b0cc372..e5e646e9 100644 --- a/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt +++ b/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt @@ -18,37 +18,55 @@ package com.android.ai.catalog.ui import android.content.Intent import android.util.Log import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TwoRowsTopAppBar +import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.android.ai.catalog.R import com.android.ai.catalog.domain.sampleCatalog +import com.android.ai.uicomponent.PrimaryButton import com.google.firebase.FirebaseApp import kotlinx.serialization.Serializable -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun CatalogApp(modifier: Modifier = Modifier) { val context = LocalContext.current @@ -60,19 +78,43 @@ fun CatalogApp(modifier: Modifier = Modifier) { startDestination = HomeScreen, ) { composable { + val topAppBarState = rememberTopAppBarState() + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(topAppBarState) Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - TopAppBar( + TwoRowsTopAppBar( colors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = MaterialTheme.colorScheme.surface, titleContentColor = MaterialTheme.colorScheme.primary, ), - title = { + title = { expanded -> + if (expanded) { + Row ( + modifier = Modifier.height(40.dp).width(58.dp).background( + color = MaterialTheme.colorScheme.primary, + shape = RoundedCornerShape(24.dp) + ) + ) { + Icon( + painter = painterResource(com.android.ai.uicomponent.R.drawable.ic_spark), + contentDescription = null, + modifier = Modifier.padding(10.dp), + tint = MaterialTheme.colorScheme.onPrimary, + ) + } + Spacer(modifier = Modifier.height(12.dp)) + } Text( - text = stringResource(id = R.string.top_bar_title), - style = MaterialTheme.typography.titleLarge, + text = stringResource(id = if (expanded) R.string.top_bar_title_expanded else R.string.top_bar_title), + style = if (expanded) MaterialTheme.typography.displaySmall else MaterialTheme.typography.headlineMedium, color = MaterialTheme.colorScheme.onSurface, + maxLines = if (expanded) 2 else 1, + modifier = Modifier.padding(bottom = 12.dp) ) }, + scrollBehavior = scrollBehavior ) }, ) { innerPadding -> diff --git a/ai-catalog/app/src/main/res/values/strings.xml b/ai-catalog/app/src/main/res/values/strings.xml index 49370110..b9b32aaa 100644 --- a/ai-catalog/app/src/main/res/values/strings.xml +++ b/ai-catalog/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ Polish text with Gemini Nano Proofread and rewrite short content on-device with GenAI API powered by Gemini Nano Android AI Samples + Android\nAI Samples Open sample Image generation with Imagen Generate images with Imagen, Google image generation model From 13ad23a691f3e436f0238eea68df642248445779 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Thu, 11 Sep 2025 11:06:25 -0700 Subject: [PATCH 2/2] Update expanded states and pill icon --- .../com/android/ai/catalog/ui/CatalogApp.kt | 66 ++++++++++++------- .../src/main/res/drawable/spark_android.xml | 10 +++ 2 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 ai-catalog/app/src/main/res/drawable/spark_android.xml diff --git a/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt b/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt index e5e646e9..cbdbb720 100644 --- a/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt +++ b/ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt @@ -19,11 +19,9 @@ import android.content.Intent import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width @@ -38,7 +36,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TwoRowsTopAppBar import androidx.compose.material3.rememberTopAppBarState @@ -47,8 +44,8 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.ContentScale @@ -62,7 +59,6 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.android.ai.catalog.R import com.android.ai.catalog.domain.sampleCatalog -import com.android.ai.uicomponent.PrimaryButton import com.google.firebase.FirebaseApp import kotlinx.serialization.Serializable @@ -91,28 +87,29 @@ fun CatalogApp(modifier: Modifier = Modifier) { ), title = { expanded -> if (expanded) { - Row ( - modifier = Modifier.height(40.dp).width(58.dp).background( - color = MaterialTheme.colorScheme.primary, - shape = RoundedCornerShape(24.dp) - ) - ) { - Icon( - painter = painterResource(com.android.ai.uicomponent.R.drawable.ic_spark), - contentDescription = null, - modifier = Modifier.padding(10.dp), - tint = MaterialTheme.colorScheme.onPrimary, + AppBarPill() + Spacer(modifier = Modifier.height(12.dp)) + Text( + text = stringResource(id = R.string.top_bar_title_expanded), + style = MaterialTheme.typography.displaySmall, + color = MaterialTheme.colorScheme.onSurface, + maxLines = 2, + modifier = Modifier.padding(bottom = 12.dp) + ) + } else { + Row { + AppBarPill() + Spacer(modifier = Modifier.width(12.dp)) + Text( + text = stringResource(id = R.string.top_bar_title), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface, + maxLines = 1, + modifier = Modifier.align(Alignment.CenterVertically) ) } - Spacer(modifier = Modifier.height(12.dp)) } - Text( - text = stringResource(id = if (expanded) R.string.top_bar_title_expanded else R.string.top_bar_title), - style = if (expanded) MaterialTheme.typography.displaySmall else MaterialTheme.typography.headlineMedium, - color = MaterialTheme.colorScheme.onSurface, - maxLines = if (expanded) 2 else 1, - modifier = Modifier.padding(bottom = 12.dp) - ) + }, scrollBehavior = scrollBehavior ) @@ -170,6 +167,27 @@ fun CatalogApp(modifier: Modifier = Modifier) { @Serializable object HomeScreen + +@Composable +fun AppBarPill() { + Row( + modifier = Modifier + .height(40.dp) + .width(58.dp) + .background( + color = MaterialTheme.colorScheme.primary, + shape = RoundedCornerShape(24.dp), + ), + ) { + Icon( + painter = painterResource(R.drawable.spark_android), + contentDescription = null, + modifier = Modifier.padding(10.dp), + tint = MaterialTheme.colorScheme.onPrimary, + ) + } +} + @Composable fun FirebaseRequiredAlert(onDismiss: () -> Unit = {}, onOpenFirebaseDocClick: () -> Unit = {}) { AlertDialog( diff --git a/ai-catalog/app/src/main/res/drawable/spark_android.xml b/ai-catalog/app/src/main/res/drawable/spark_android.xml new file mode 100644 index 00000000..4a3344de --- /dev/null +++ b/ai-catalog/app/src/main/res/drawable/spark_android.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file