Skip to content

Commit a665f40

Browse files
Redesign (#115)
1 parent 7b1d972 commit a665f40

File tree

284 files changed

+6032
-3241
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

284 files changed

+6032
-3241
lines changed

ai-catalog/app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ dependencies {
8080
implementation(libs.firebase.ai)
8181
ksp(libs.hilt.compiler)
8282

83+
implementation(project(":ui-component"))
8384
implementation(project(":samples:gemini-multimodal"))
8485
implementation(project(":samples:gemini-chatbot"))
8586
implementation(project(":samples:genai-summarization"))

ai-catalog/app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
android:fullBackupContent="@xml/backup_rules"
1010
android:icon="@mipmap/ic_launcher"
1111
android:label="@string/app_name"
12-
android:roundIcon="@mipmap/ic_launcher_round"
1312
android:supportsRtl="true"
1413
android:theme="@style/Theme.AISampleCatalog"
1514
tools:targetApi="31"

ai-catalog/app/src/main/java/com/android/ai/catalog/MainActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import androidx.activity.enableEdgeToEdge
2222
import androidx.compose.foundation.layout.fillMaxSize
2323
import androidx.compose.ui.Modifier
2424
import com.android.ai.catalog.ui.CatalogApp
25-
import com.android.ai.catalog.ui.theme.AISampleCatalogTheme
25+
import com.android.ai.theme.AISampleCatalogTheme
2626
import dagger.hilt.android.AndroidEntryPoint
2727

2828
@AndroidEntryPoint

ai-catalog/app/src/main/java/com/android/ai/catalog/ui/domain/SampleCatalog.kt renamed to ai-catalog/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.android.ai.catalog.ui.domain
16+
package com.android.ai.catalog.domain
1717

18+
import android.Manifest
19+
import androidx.annotation.DrawableRes
20+
import androidx.annotation.RequiresPermission
1821
import androidx.annotation.StringRes
1922
import androidx.compose.runtime.Composable
2023
import androidx.compose.ui.graphics.Color
@@ -23,16 +26,17 @@ import com.android.ai.samples.geminichatbot.GeminiChatbotScreen
2326
import com.android.ai.samples.geminiimagechat.GeminiImageChatScreen
2427
import com.android.ai.samples.geminilivetodo.ui.TodoScreen
2528
import com.android.ai.samples.geminimultimodal.ui.GeminiMultimodalScreen
26-
import com.android.ai.samples.geminivideometadatacreation.VideoMetadataCreationScreen
27-
import com.android.ai.samples.geminivideosummary.VideoSummarizationScreen
29+
import com.android.ai.samples.geminivideometadatacreation.ui.VideoMetadataCreationScreen
30+
import com.android.ai.samples.geminivideosummary.ui.VideoSummarizationScreen
2831
import com.android.ai.samples.genai_image_description.GenAIImageDescriptionScreen
2932
import com.android.ai.samples.genai_summarization.GenAISummarizationScreen
3033
import com.android.ai.samples.genai_writing_assistance.GenAIWritingAssistanceScreen
3134
import com.android.ai.samples.imagen.ui.ImagenScreen
3235
import com.android.ai.samples.imagenediting.ui.ImagenEditingScreen
3336
import com.android.ai.samples.magicselfie.ui.MagicSelfieScreen
37+
import com.android.ai.theme.extendedColorScheme
3438

35-
@androidx.annotation.RequiresPermission(android.Manifest.permission.RECORD_AUDIO)
39+
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
3640
val sampleCatalog = listOf(
3741
SampleCatalogItem(
3842
title = R.string.gemini_image_chat,
@@ -49,6 +53,8 @@ val sampleCatalog = listOf(
4953
sampleEntryScreen = { GeminiMultimodalScreen() },
5054
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
5155
needsFirebase = true,
56+
isFeatured = true,
57+
keyArt = R.drawable.img_keyart_multimodal,
5258
),
5359
SampleCatalogItem(
5460
title = R.string.gemini_chatbot_sample_title,
@@ -57,27 +63,31 @@ val sampleCatalog = listOf(
5763
sampleEntryScreen = { GeminiChatbotScreen() },
5864
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
5965
needsFirebase = true,
66+
keyArt = R.drawable.img_keyart_chatbot,
6067
),
6168
SampleCatalogItem(
6269
title = R.string.genai_summarization_sample_title,
6370
description = R.string.genai_summarization_sample_description,
6471
route = "GenAISummarizationScreen",
6572
sampleEntryScreen = { GenAISummarizationScreen() },
6673
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.ML_KIT),
74+
keyArt = R.drawable.img_keyart_summary,
6775
),
6876
SampleCatalogItem(
6977
title = R.string.genai_image_description_sample_title,
7078
description = R.string.genai_image_description_sample_description,
7179
route = "GenAIImageDescriptionScreen",
7280
sampleEntryScreen = { GenAIImageDescriptionScreen() },
7381
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.ML_KIT),
82+
keyArt = R.drawable.img_keyart_img_desc,
7483
),
7584
SampleCatalogItem(
7685
title = R.string.genai_writing_assistance_sample_title,
7786
description = R.string.genai_writing_assistance_sample_description,
7887
route = "GenAIWritingAssistanceScreen",
7988
sampleEntryScreen = { GenAIWritingAssistanceScreen() },
8089
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.ML_KIT),
90+
keyArt = R.drawable.img_keyart_text,
8191
),
8292
SampleCatalogItem(
8393
title = R.string.imagen_sample_title,
@@ -86,14 +96,16 @@ val sampleCatalog = listOf(
8696
sampleEntryScreen = { ImagenScreen() },
8797
tags = listOf(SampleTags.IMAGEN, SampleTags.FIREBASE),
8898
needsFirebase = true,
99+
keyArt = R.drawable.img_keyart_imagen,
89100
),
90101
SampleCatalogItem(
91102
title = R.string.imagen_editing_sample_title,
92103
description = R.string.imagen_editing_sample_description,
93104
route = "ImagenMaskEditing",
94105
sampleEntryScreen = { ImagenEditingScreen() },
95-
tags = listOf(SampleTags.IMAGEN, SampleTags.FIREBASE, SampleTags.MEDIA3),
106+
tags = listOf(SampleTags.IMAGEN, SampleTags.FIREBASE),
96107
needsFirebase = true,
108+
keyArt = R.drawable.img_keyart_imagen,
97109
),
98110
SampleCatalogItem(
99111
title = R.string.magic_selfie_sample_title,
@@ -102,6 +114,7 @@ val sampleCatalog = listOf(
102114
sampleEntryScreen = { MagicSelfieScreen() },
103115
tags = listOf(SampleTags.IMAGEN, SampleTags.FIREBASE, SampleTags.ML_KIT),
104116
needsFirebase = true,
117+
keyArt = R.drawable.img_keyart_magic_selfie,
105118
),
106119
SampleCatalogItem(
107120
title = R.string.gemini_video_summarization_sample_title,
@@ -118,6 +131,7 @@ val sampleCatalog = listOf(
118131
sampleEntryScreen = { VideoMetadataCreationScreen() },
119132
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE, SampleTags.MEDIA3),
120133
needsFirebase = true,
134+
keyArt = R.drawable.img_keyart_video_summary,
121135
),
122136
SampleCatalogItem(
123137
title = R.string.gemini_live_todo_title,
@@ -126,6 +140,7 @@ val sampleCatalog = listOf(
126140
sampleEntryScreen = { TodoScreen() },
127141
tags = listOf(SampleTags.GEMINI_FLASH, SampleTags.FIREBASE),
128142
needsFirebase = true,
143+
keyArt = R.drawable.img_keyart_todo,
129144
),
130145

131146
// To create a new sample entry, add a new SampleCatalogItem here.
@@ -138,17 +153,18 @@ data class SampleCatalogItem(
138153
val sampleEntryScreen: @Composable () -> Unit,
139154
val tags: List<SampleTags> = emptyList(),
140155
val needsFirebase: Boolean = false,
156+
val isFeatured: Boolean = false,
157+
@DrawableRes val keyArt: Int? = null,
141158
)
142159

143160
enum class SampleTags(
144161
val label: String,
145162
val backgroundColor: Color,
146-
val textColor: Color,
147163
) {
148-
FIREBASE("Firebase", Color(0xFFFF9100), Color.White),
149-
GEMINI_FLASH("Gemini Flash", Color(0xFF4285F4), Color.White),
150-
GEMINI_NANO("Gemini Nano", Color(0xFF7abafe), Color.White),
151-
IMAGEN("Imagen", Color(0xFF7CB342), Color.White),
152-
MEDIA3("Media3", Color(0xFF7CB584), Color.White),
153-
ML_KIT("ML Kit", Color.White, Color(0xFF4285F4)),
164+
FIREBASE("Firebase", extendedColorScheme.firebase),
165+
GEMINI_FLASH("Gemini Flash", extendedColorScheme.geminiProFlash),
166+
GEMINI_NANO("Gemini Nano", extendedColorScheme.geminiNano),
167+
IMAGEN("Imagen", extendedColorScheme.imagen),
168+
MEDIA3("Media3", extendedColorScheme.media3),
169+
ML_KIT("ML Kit", extendedColorScheme.mLKit),
154170
}

ai-catalog/app/src/main/java/com/android/ai/catalog/ui/CatalogApp.kt

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,89 +17,130 @@ package com.android.ai.catalog.ui
1717

1818
import android.content.Intent
1919
import android.util.Log
20+
import androidx.compose.foundation.Image
2021
import androidx.compose.foundation.background
21-
import androidx.compose.foundation.layout.Box
22-
import androidx.compose.foundation.layout.Column
2322
import androidx.compose.foundation.layout.Row
2423
import androidx.compose.foundation.layout.Spacer
24+
import androidx.compose.foundation.layout.fillMaxSize
2525
import androidx.compose.foundation.layout.fillMaxWidth
26+
import androidx.compose.foundation.layout.height
2627
import androidx.compose.foundation.layout.padding
2728
import androidx.compose.foundation.layout.width
2829
import androidx.compose.foundation.lazy.LazyColumn
2930
import androidx.compose.foundation.lazy.items
3031
import androidx.compose.foundation.shape.RoundedCornerShape
3132
import androidx.compose.material3.AlertDialog
32-
import androidx.compose.material3.ElevatedCard
3333
import androidx.compose.material3.ExperimentalMaterial3Api
34+
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
35+
import androidx.compose.material3.Icon
3436
import androidx.compose.material3.MaterialTheme
3537
import androidx.compose.material3.Scaffold
3638
import androidx.compose.material3.Text
3739
import androidx.compose.material3.TextButton
38-
import androidx.compose.material3.TopAppBar
3940
import androidx.compose.material3.TopAppBarDefaults
41+
import androidx.compose.material3.TwoRowsTopAppBar
42+
import androidx.compose.material3.rememberTopAppBarState
4043
import androidx.compose.runtime.Composable
4144
import androidx.compose.runtime.getValue
4245
import androidx.compose.runtime.mutableStateOf
4346
import androidx.compose.runtime.remember
4447
import androidx.compose.runtime.setValue
48+
import androidx.compose.ui.Alignment
4549
import androidx.compose.ui.Modifier
50+
import androidx.compose.ui.graphics.Color
51+
import androidx.compose.ui.input.nestedscroll.nestedScroll
52+
import androidx.compose.ui.layout.ContentScale
4653
import androidx.compose.ui.platform.LocalContext
54+
import androidx.compose.ui.res.painterResource
4755
import androidx.compose.ui.res.stringResource
48-
import androidx.compose.ui.text.font.FontWeight
4956
import androidx.compose.ui.unit.dp
50-
import androidx.compose.ui.unit.sp
5157
import androidx.core.net.toUri
5258
import androidx.navigation.compose.NavHost
5359
import androidx.navigation.compose.composable
5460
import androidx.navigation.compose.rememberNavController
5561
import com.android.ai.catalog.R
56-
import com.android.ai.catalog.ui.domain.SampleCatalogItem
57-
import com.android.ai.catalog.ui.domain.sampleCatalog
62+
import com.android.ai.catalog.domain.sampleCatalog
5863
import com.google.firebase.FirebaseApp
5964
import kotlinx.serialization.Serializable
6065

61-
@OptIn(ExperimentalMaterial3Api::class)
66+
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
6267
@Composable
6368
fun CatalogApp(modifier: Modifier = Modifier) {
6469
val context = LocalContext.current
6570
val navController = rememberNavController()
66-
6771
var isDialogOpened by remember { mutableStateOf(false) }
6872

6973
NavHost(
7074
navController = navController,
7175
startDestination = HomeScreen,
7276
) {
7377
composable<HomeScreen> {
78+
val topAppBarState = rememberTopAppBarState()
79+
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(topAppBarState)
7480
Scaffold(
81+
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
7582
topBar = {
76-
TopAppBar(
83+
TwoRowsTopAppBar(
7784
colors = TopAppBarDefaults.topAppBarColors(
78-
containerColor = MaterialTheme.colorScheme.primaryContainer,
85+
containerColor = Color.Transparent,
86+
scrolledContainerColor = MaterialTheme.colorScheme.surface,
7987
titleContentColor = MaterialTheme.colorScheme.primary,
8088
),
81-
title = {
82-
Text(text = stringResource(id = R.string.top_bar_title))
89+
navigationIcon = { AppBarPill() },
90+
title = { expanded ->
91+
if (expanded) {
92+
Text(
93+
text = stringResource(id = R.string.top_bar_title_expanded),
94+
style = MaterialTheme.typography.displaySmall,
95+
color = MaterialTheme.colorScheme.onSurface,
96+
maxLines = 2,
97+
modifier = Modifier.padding(bottom = 12.dp),
98+
)
99+
} else {
100+
Row {
101+
Spacer(modifier = Modifier.width(12.dp))
102+
Text(
103+
text = stringResource(id = R.string.top_bar_title),
104+
style = MaterialTheme.typography.titleLarge,
105+
color = MaterialTheme.colorScheme.onSurface,
106+
maxLines = 1,
107+
modifier = Modifier.align(Alignment.CenterVertically),
108+
)
109+
}
110+
}
83111
},
112+
scrollBehavior = scrollBehavior,
84113
)
85114
},
86115
) { innerPadding ->
116+
Image(
117+
painter = painterResource(id = R.drawable.img_bg_landing),
118+
contentDescription = "Background Image",
119+
modifier = Modifier.fillMaxSize(),
120+
contentScale = ContentScale.FillWidth,
121+
)
87122
LazyColumn(
88123
contentPadding = innerPadding,
124+
modifier = Modifier.fillMaxWidth(),
125+
horizontalAlignment = Alignment.CenterHorizontally,
89126
) {
90127
items(sampleCatalog) {
91-
CatalogListItem(catalogItem = it) {
128+
val onClick = {
92129
if (it.needsFirebase && !isFirebaseInitialized()) {
93130
isDialogOpened = true
94131
} else {
95132
navController.navigate(it.route)
96133
}
97134
}
135+
if (it.isFeatured) {
136+
CatalogWideCard(catalogItem = it, onClick = onClick)
137+
} else {
138+
CatalogRowCard(catalogItem = it, onClick = onClick)
139+
}
98140
}
99141
}
100142
}
101143
}
102-
103144
sampleCatalog.forEach {
104145
val catalogItem = it
105146
composable(catalogItem.route) {
@@ -123,59 +164,27 @@ fun CatalogApp(modifier: Modifier = Modifier) {
123164
}
124165
}
125166

167+
@Serializable
168+
object HomeScreen
169+
126170
@Composable
127-
fun CatalogListItem(catalogItem: SampleCatalogItem, onButtonClick: () -> Unit) {
128-
val context = LocalContext.current
129-
ElevatedCard(
130-
modifier = Modifier.padding(18.dp),
131-
onClick = {
132-
onButtonClick()
133-
},
134-
) {
135-
Column(
136-
Modifier.padding(15.dp),
137-
) {
138-
Text(
139-
modifier = Modifier
140-
.fillMaxWidth()
141-
.padding(bottom = 8.dp),
142-
fontSize = 20.sp,
143-
fontWeight = FontWeight.Bold,
144-
text = context.getString(catalogItem.title),
145-
)
146-
Text(
147-
modifier = Modifier.padding(bottom = 8.dp),
148-
text = context.getString(catalogItem.description),
149-
)
150-
Row {
151-
Spacer(Modifier.weight(1f))
152-
catalogItem.tags.forEach {
153-
Spacer(Modifier.width(8.dp))
154-
Box(
155-
modifier = Modifier
156-
.background(
157-
color = it.backgroundColor,
158-
shape = RoundedCornerShape(
159-
8.dp,
160-
),
161-
)
162-
.padding(start = 4.dp, end = 4.dp),
163-
) {
164-
Text(
165-
fontSize = 9.sp,
166-
text = it.label,
167-
color = it.textColor,
168-
)
169-
}
170-
}
171-
}
172-
}
171+
fun AppBarPill() {
172+
Row {
173+
Spacer(Modifier.width(12.dp))
174+
Icon(
175+
painter = painterResource(R.drawable.spark_android),
176+
contentDescription = null,
177+
modifier = Modifier.height(40.dp)
178+
.width(58.dp)
179+
.background(
180+
color = MaterialTheme.colorScheme.primary,
181+
shape = RoundedCornerShape(24.dp),
182+
).padding(10.dp),
183+
tint = MaterialTheme.colorScheme.onPrimary,
184+
)
173185
}
174186
}
175187

176-
@Serializable
177-
object HomeScreen
178-
179188
@Composable
180189
fun FirebaseRequiredAlert(onDismiss: () -> Unit = {}, onOpenFirebaseDocClick: () -> Unit = {}) {
181190
AlertDialog(

0 commit comments

Comments
 (0)