From 5b8af594eb1470d0fa3b16dc9a78ff356574224b Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Mon, 20 Nov 2023 12:22:07 +0000 Subject: [PATCH 1/5] Update animation codelab * Use Material 3 * Change colors to be a bit softer * Enable Edge-to-Edge --- AnimationCodelab/finished/build.gradle | 16 +- .../android/codelab/animation/MainActivity.kt | 2 + .../android/codelab/animation/ui/Color.kt | 13 +- .../android/codelab/animation/ui/Theme.kt | 18 +- .../android/codelab/animation/ui/home/Home.kt | 215 ++++++++++-------- AnimationCodelab/start/build.gradle | 16 +- .../android/codelab/animation/MainActivity.kt | 2 + .../android/codelab/animation/ui/Color.kt | 13 +- .../android/codelab/animation/ui/Theme.kt | 17 +- .../android/codelab/animation/ui/home/Home.kt | 215 ++++++++++-------- .../start/src/main/res/values/themes.xml | 2 - README.md | 2 +- 12 files changed, 275 insertions(+), 256 deletions(-) diff --git a/AnimationCodelab/finished/build.gradle b/AnimationCodelab/finished/build.gradle index 23fba0f11..f59ad5422 100644 --- a/AnimationCodelab/finished/build.gradle +++ b/AnimationCodelab/finished/build.gradle @@ -21,11 +21,11 @@ plugins { android { namespace "com.example.android.codelab.animation" - compileSdkVersion 34 + compileSdk 34 defaultConfig { applicationId 'com.example.android.codelab.animation' minSdkVersion 21 - targetSdkVersion 33 + targetSdk 34 versionCode 1 versionName '1.0' } @@ -51,17 +51,7 @@ dependencies { implementation 'androidx.activity:activity-compose:1.8.1' implementation 'androidx.core:core-ktx:1.12.0' implementation "androidx.compose.ui:ui" - implementation "androidx.compose.material:material" + implementation "androidx.compose.material3:material3" implementation "androidx.compose.ui:ui-tooling-preview" debugImplementation "androidx.compose.ui:ui-tooling" } - -// Compiler flag to use experimental Compose APIs -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - jvmTarget = "1.8" - freeCompilerArgs += [ - "-opt-in=kotlin.RequiresOptIn" - ] - } -} diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/MainActivity.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/MainActivity.kt index b364f3978..1ad646112 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/MainActivity.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/MainActivity.kt @@ -19,6 +19,7 @@ package com.example.android.codelab.animation import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge import com.example.android.codelab.animation.ui.AnimationCodelabTheme import com.example.android.codelab.animation.ui.home.Home @@ -26,6 +27,7 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() setContent { AnimationCodelabTheme { Home() diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Color.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Color.kt index a2fa16c58..f1c0e0b07 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Color.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Color.kt @@ -18,10 +18,11 @@ package com.example.android.codelab.animation.ui import androidx.compose.ui.graphics.Color -val Purple100 = Color(0xFFE1BEE7) -val Purple500 = Color(0xFF6200EE) -val Purple700 = Color(0xFF3700B3) -val Teal200 = Color(0xFF03DAC5) -val Green300 = Color(0xFF81C784) -val Green800 = Color(0xFF2E7D32) val Amber600 = Color(0xFFFFB300) + +val Melon = Color(0xFFfec5bb) +val PaleDogwood = Color(0xFFfcd5ce) +val Seashell = Color(0xFFf8edeb) +val Peach = Color(0xFFfec89a) +val Green = Color(0xFFd8e2dc) +val GreenLight = Color(0xFFEBF1EE) diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt index 12a0fcd49..b1c5e4735 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt @@ -16,19 +16,21 @@ package com.example.android.codelab.animation.ui -import androidx.compose.material.MaterialTheme -import androidx.compose.material.lightColors +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color @Composable fun AnimationCodelabTheme(content: @Composable () -> Unit) { - val colors = lightColors( - primary = Purple500, - primaryVariant = Purple700, - secondary = Teal200 + val colors = lightColorScheme( + primary = Melon, + primaryContainer = PaleDogwood, + onPrimary = Color.Black, + secondary = Peach ) MaterialTheme( - colors = colors, + colorScheme = colors, content = content ) -} +} \ No newline at end of file diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 5ca4a0deb..17c185317 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -49,14 +49,20 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState @@ -64,17 +70,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.FloatingActionButton -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.Surface -import androidx.compose.material.TabPosition -import androidx.compose.material.TabRow -import androidx.compose.material.Text -import androidx.compose.material.TextButton import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccountBox import androidx.compose.material.icons.filled.Check @@ -82,11 +77,22 @@ import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.TabPosition +import androidx.compose.material3.TabRow +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.key +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -114,10 +120,10 @@ import androidx.compose.ui.unit.sp import com.example.android.codelab.animation.R import com.example.android.codelab.animation.ui.Amber600 import com.example.android.codelab.animation.ui.AnimationCodelabTheme -import com.example.android.codelab.animation.ui.Green300 -import com.example.android.codelab.animation.ui.Green800 -import com.example.android.codelab.animation.ui.Purple100 -import com.example.android.codelab.animation.ui.Purple700 +import com.example.android.codelab.animation.ui.Green +import com.example.android.codelab.animation.ui.GreenLight +import com.example.android.codelab.animation.ui.PaleDogwood +import com.example.android.codelab.animation.ui.Seashell import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -178,7 +184,7 @@ fun Home() { val lazyListState = rememberLazyListState() // The background color. The value is changed by the current tab. - val backgroundColor by animateColorAsState(if (tabPage == TabPage.Home) Purple100 else Green300) + val backgroundColor by animateColorAsState(if (tabPage == TabPage.Home) Seashell else GreenLight) // The coroutine scope for event handlers calling suspend functions. val coroutineScope = rememberCoroutineScope() @@ -190,7 +196,7 @@ fun Home() { onTabSelected = { tabPage = it } ) }, - backgroundColor = backgroundColor, + containerColor = backgroundColor, floatingActionButton = { HomeFloatingActionButton( extended = lazyListState.isScrollingUp(), @@ -202,69 +208,75 @@ fun Home() { ) } ) { padding -> - LazyColumn( - contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp), - state = lazyListState, - modifier = Modifier.padding(padding) - ) { - // Weather - item { Header(title = stringResource(R.string.weather)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - item { - Surface( - modifier = Modifier.fillMaxWidth(), - elevation = 2.dp - ) { - if (weatherLoading) { - LoadingRow() - } else { - WeatherRow(onRefresh = { - coroutineScope.launch { - loadWeather() - } - }) + Box(Modifier + .consumeWindowInsets( + WindowInsets.safeDrawing.only(WindowInsetsSides.Top) + ) + .padding(padding)) { + + LazyColumn( + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp), + state = lazyListState + ) { + // Weather + item { Header(title = stringResource(R.string.weather)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + item { + Surface( + modifier = Modifier.fillMaxWidth(), + shadowElevation = 2.dp + ) { + if (weatherLoading) { + LoadingRow() + } else { + WeatherRow(onRefresh = { + coroutineScope.launch { + loadWeather() + } + }) + } } } - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Topics - item { Header(title = stringResource(R.string.topics)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - items(allTopics) { topic -> - TopicRow( - topic = topic, - expanded = expandedTopic == topic, - onClick = { - expandedTopic = if (expandedTopic == topic) null else topic - } - ) - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Tasks - item { Header(title = stringResource(R.string.tasks)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - if (tasks.isEmpty()) { - item { - TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { - Text(stringResource(R.string.add_tasks)) + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Topics + item { Header(title = stringResource(R.string.topics)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + items(allTopics) { topic -> + TopicRow( + topic = topic, + expanded = expandedTopic == topic, + onClick = { + expandedTopic = if (expandedTopic == topic) null else topic + } + ) + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Tasks + item { Header(title = stringResource(R.string.tasks)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + if (tasks.isEmpty()) { + item { + TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { + Text(stringResource(R.string.add_tasks)) + } } } - } - items(count = tasks.size) { i -> - val task = tasks.getOrNull(i) - if (task != null) { - key(task) { - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) + items(count = tasks.size) { i -> + val task = tasks.getOrNull(i) + if (task != null) { + key(task) { + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) + } } } } + EditMessage(editMessageShown) } - EditMessage(editMessageShown) } } @@ -321,8 +333,8 @@ private fun EditMessage(shown: Boolean) { ) { Surface( modifier = Modifier.fillMaxWidth(), - color = MaterialTheme.colors.secondary, - elevation = 4.dp + color = MaterialTheme.colorScheme.secondary, + shadowElevation = 4.dp ) { Text( text = stringResource(R.string.edit_message), @@ -337,8 +349,8 @@ private fun EditMessage(shown: Boolean) { */ @Composable private fun LazyListState.isScrollingUp(): Boolean { - var previousIndex by remember(this) { mutableStateOf(firstVisibleItemIndex) } - var previousScrollOffset by remember(this) { mutableStateOf(firstVisibleItemScrollOffset) } + var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) } + var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) } return remember(this) { derivedStateOf { if (previousIndex != firstVisibleItemIndex) { @@ -365,7 +377,7 @@ private fun Header( Text( text = title, modifier = Modifier.semantics { heading() }, - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.headlineLarge ) } @@ -376,14 +388,13 @@ private fun Header( * @param expanded Whether the row should be shown expanded with the topic body. * @param onClick Called when the row is clicked. */ -@OptIn(ExperimentalMaterialApi::class) @Composable private fun TopicRow(topic: String, expanded: Boolean, onClick: () -> Unit) { TopicRowSpacer(visible = expanded) Surface( modifier = Modifier .fillMaxWidth(), - elevation = 2.dp, + shadowElevation = 2.dp, onClick = onClick ) { Column( @@ -401,7 +412,7 @@ private fun TopicRow(topic: String, expanded: Boolean, onClick: () -> Unit) { Spacer(modifier = Modifier.width(16.dp)) Text( text = topic, - style = MaterialTheme.typography.body1 + style = MaterialTheme.typography.bodySmall ) } if (expanded) { @@ -439,23 +450,27 @@ private fun HomeTabBar( tabPage: TabPage, onTabSelected: (tabPage: TabPage) -> Unit ) { - TabRow( - selectedTabIndex = tabPage.ordinal, - backgroundColor = backgroundColor, - indicator = { tabPositions -> - HomeTabIndicator(tabPositions, tabPage) + Column { + Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) + TabRow( + selectedTabIndex = tabPage.ordinal, + containerColor = backgroundColor, + contentColor = MaterialTheme.colorScheme.onPrimary, + indicator = { tabPositions -> + HomeTabIndicator(tabPositions, tabPage) + } + ) { + HomeTab( + icon = Icons.Default.Home, + title = stringResource(R.string.home), + onClick = { onTabSelected(TabPage.Home) } + ) + HomeTab( + icon = Icons.Default.AccountBox, + title = stringResource(R.string.work), + onClick = { onTabSelected(TabPage.Work) } + ) } - ) { - HomeTab( - icon = Icons.Default.Home, - title = stringResource(R.string.home), - onClick = { onTabSelected(TabPage.Home) } - ) - HomeTab( - icon = Icons.Default.AccountBox, - title = stringResource(R.string.work), - onClick = { onTabSelected(TabPage.Work) } - ) } } @@ -509,7 +524,7 @@ private fun HomeTabIndicator( val color by transition.animateColor( label = "Border color" ) { page -> - if (page == TabPage.Home) Purple700 else Green800 + if (page == TabPage.Home) PaleDogwood else Green } Box( Modifier @@ -648,7 +663,7 @@ private fun TaskRow(task: String, onRemove: () -> Unit) { modifier = Modifier .fillMaxWidth() .swipeToDismiss(onRemove), - elevation = 2.dp + shadowElevation = 2.dp ) { Row( modifier = Modifier @@ -662,7 +677,7 @@ private fun TaskRow(task: String, onRemove: () -> Unit) { Spacer(modifier = Modifier.width(16.dp)) Text( text = task, - style = MaterialTheme.typography.body1 + style = MaterialTheme.typography.bodySmall ) } } @@ -736,7 +751,7 @@ private fun Modifier.swipeToDismiss( @Composable private fun PreviewHomeTabBar() { HomeTabBar( - backgroundColor = Purple100, + backgroundColor = PaleDogwood, tabPage = TabPage.Home, onTabSelected = {} ) diff --git a/AnimationCodelab/start/build.gradle b/AnimationCodelab/start/build.gradle index 23fba0f11..f59ad5422 100644 --- a/AnimationCodelab/start/build.gradle +++ b/AnimationCodelab/start/build.gradle @@ -21,11 +21,11 @@ plugins { android { namespace "com.example.android.codelab.animation" - compileSdkVersion 34 + compileSdk 34 defaultConfig { applicationId 'com.example.android.codelab.animation' minSdkVersion 21 - targetSdkVersion 33 + targetSdk 34 versionCode 1 versionName '1.0' } @@ -51,17 +51,7 @@ dependencies { implementation 'androidx.activity:activity-compose:1.8.1' implementation 'androidx.core:core-ktx:1.12.0' implementation "androidx.compose.ui:ui" - implementation "androidx.compose.material:material" + implementation "androidx.compose.material3:material3" implementation "androidx.compose.ui:ui-tooling-preview" debugImplementation "androidx.compose.ui:ui-tooling" } - -// Compiler flag to use experimental Compose APIs -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - jvmTarget = "1.8" - freeCompilerArgs += [ - "-opt-in=kotlin.RequiresOptIn" - ] - } -} diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/MainActivity.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/MainActivity.kt index b364f3978..1ad646112 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/MainActivity.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/MainActivity.kt @@ -19,6 +19,7 @@ package com.example.android.codelab.animation import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge import com.example.android.codelab.animation.ui.AnimationCodelabTheme import com.example.android.codelab.animation.ui.home.Home @@ -26,6 +27,7 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() setContent { AnimationCodelabTheme { Home() diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Color.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Color.kt index a2fa16c58..2f33317e6 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Color.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Color.kt @@ -18,10 +18,11 @@ package com.example.android.codelab.animation.ui import androidx.compose.ui.graphics.Color -val Purple100 = Color(0xFFE1BEE7) -val Purple500 = Color(0xFF6200EE) -val Purple700 = Color(0xFF3700B3) -val Teal200 = Color(0xFF03DAC5) -val Green300 = Color(0xFF81C784) -val Green800 = Color(0xFF2E7D32) val Amber600 = Color(0xFFFFB300) + +val Melon = Color(0xFFfec5bb) +val PaleDogwood = Color(0xFFfcd5ce) +val Seashell = Color(0xFFf8edeb) +val Peach = Color(0xFFfec89a) +val Green = Color(0xFFd8e2dc) +val GreenLight = Color(0xFFEBF1EE) \ No newline at end of file diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt index 12a0fcd49..a1ca1410c 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt @@ -16,19 +16,22 @@ package com.example.android.codelab.animation.ui -import androidx.compose.material.MaterialTheme -import androidx.compose.material.lightColors +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color @Composable fun AnimationCodelabTheme(content: @Composable () -> Unit) { - val colors = lightColors( - primary = Purple500, - primaryVariant = Purple700, - secondary = Teal200 + val colors = lightColorScheme( + primary = Melon, + primaryContainer = PaleDogwood, + onPrimary = Color.Black, + secondary = Peach ) MaterialTheme( - colors = colors, + colorScheme = colors, content = content ) } + diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index ecd607065..829dc78a6 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -30,14 +30,20 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState @@ -45,17 +51,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.ExperimentalMaterialApi -import androidx.compose.material.FloatingActionButton -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold -import androidx.compose.material.Surface -import androidx.compose.material.TabPosition -import androidx.compose.material.TabRow -import androidx.compose.material.Text -import androidx.compose.material.TextButton import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccountBox import androidx.compose.material.icons.filled.Check @@ -63,11 +58,22 @@ import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.TabPosition +import androidx.compose.material3.TabRow +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.key +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -95,10 +101,10 @@ import androidx.compose.ui.unit.sp import com.example.android.codelab.animation.R import com.example.android.codelab.animation.ui.Amber600 import com.example.android.codelab.animation.ui.AnimationCodelabTheme -import com.example.android.codelab.animation.ui.Green300 -import com.example.android.codelab.animation.ui.Green800 -import com.example.android.codelab.animation.ui.Purple100 -import com.example.android.codelab.animation.ui.Purple700 +import com.example.android.codelab.animation.ui.Green +import com.example.android.codelab.animation.ui.GreenLight +import com.example.android.codelab.animation.ui.PaleDogwood +import com.example.android.codelab.animation.ui.Seashell import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -158,7 +164,7 @@ fun Home() { // The background color. The value is changed by the current tab. // TODO 1: Animate this color change. - val backgroundColor = if (tabPage == TabPage.Home) Purple100 else Green300 + val backgroundColor = if (tabPage == TabPage.Home) Seashell else GreenLight // The coroutine scope for event handlers calling suspend functions. val coroutineScope = rememberCoroutineScope() @@ -170,7 +176,7 @@ fun Home() { onTabSelected = { tabPage = it } ) }, - backgroundColor = backgroundColor, + containerColor = backgroundColor, floatingActionButton = { HomeFloatingActionButton( extended = lazyListState.isScrollingUp(), @@ -182,69 +188,75 @@ fun Home() { ) } ) { padding -> - LazyColumn( - contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp), - state = lazyListState, - modifier = Modifier.padding(padding) - ) { - // Weather - item { Header(title = stringResource(R.string.weather)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - item { - Surface( - modifier = Modifier.fillMaxWidth(), - elevation = 2.dp - ) { - if (weatherLoading) { - LoadingRow() - } else { - WeatherRow(onRefresh = { - coroutineScope.launch { - loadWeather() - } - }) + Box(Modifier + .consumeWindowInsets( + WindowInsets.safeDrawing.only(WindowInsetsSides.Top) + ) + .padding(padding)) { + + LazyColumn( + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp), + state = lazyListState + ) { + // Weather + item { Header(title = stringResource(R.string.weather)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + item { + Surface( + modifier = Modifier.fillMaxWidth(), + shadowElevation = 2.dp + ) { + if (weatherLoading) { + LoadingRow() + } else { + WeatherRow(onRefresh = { + coroutineScope.launch { + loadWeather() + } + }) + } } } - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Topics - item { Header(title = stringResource(R.string.topics)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - items(allTopics) { topic -> - TopicRow( - topic = topic, - expanded = expandedTopic == topic, - onClick = { - expandedTopic = if (expandedTopic == topic) null else topic - } - ) - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Tasks - item { Header(title = stringResource(R.string.tasks)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - if (tasks.isEmpty()) { - item { - TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { - Text(stringResource(R.string.add_tasks)) + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Topics + item { Header(title = stringResource(R.string.topics)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + items(allTopics) { topic -> + TopicRow( + topic = topic, + expanded = expandedTopic == topic, + onClick = { + expandedTopic = if (expandedTopic == topic) null else topic + } + ) + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Tasks + item { Header(title = stringResource(R.string.tasks)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + if (tasks.isEmpty()) { + item { + TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { + Text(stringResource(R.string.add_tasks)) + } } } - } - items(count = tasks.size) { i -> - val task = tasks.getOrNull(i) - if (task != null) { - key(task) { - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) + items(count = tasks.size) { i -> + val task = tasks.getOrNull(i) + if (task != null) { + key(task) { + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) + } } } } + EditMessage(editMessageShown) } - EditMessage(editMessageShown) } } @@ -294,8 +306,8 @@ private fun EditMessage(shown: Boolean) { ) { Surface( modifier = Modifier.fillMaxWidth(), - color = MaterialTheme.colors.secondary, - elevation = 4.dp + color = MaterialTheme.colorScheme.secondary, + shadowElevation = 18.dp ) { Text( text = stringResource(R.string.edit_message), @@ -310,8 +322,8 @@ private fun EditMessage(shown: Boolean) { */ @Composable private fun LazyListState.isScrollingUp(): Boolean { - var previousIndex by remember(this) { mutableStateOf(firstVisibleItemIndex) } - var previousScrollOffset by remember(this) { mutableStateOf(firstVisibleItemScrollOffset) } + var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) } + var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) } return remember(this) { derivedStateOf { if (previousIndex != firstVisibleItemIndex) { @@ -338,7 +350,7 @@ private fun Header( Text( text = title, modifier = Modifier.semantics { heading() }, - style = MaterialTheme.typography.h5 + style = MaterialTheme.typography.headlineLarge ) } @@ -349,14 +361,13 @@ private fun Header( * @param expanded Whether the row should be shown expanded with the topic body. * @param onClick Called when the row is clicked. */ -@OptIn(ExperimentalMaterialApi::class) @Composable private fun TopicRow(topic: String, expanded: Boolean, onClick: () -> Unit) { TopicRowSpacer(visible = expanded) Surface( modifier = Modifier .fillMaxWidth(), - elevation = 2.dp, + shadowElevation = 2.dp, onClick = onClick ) { // TODO 3: Animate the size change of the content. @@ -373,7 +384,7 @@ private fun TopicRow(topic: String, expanded: Boolean, onClick: () -> Unit) { Spacer(modifier = Modifier.width(16.dp)) Text( text = topic, - style = MaterialTheme.typography.body1 + style = MaterialTheme.typography.bodySmall ) } if (expanded) { @@ -411,23 +422,27 @@ private fun HomeTabBar( tabPage: TabPage, onTabSelected: (tabPage: TabPage) -> Unit ) { - TabRow( - selectedTabIndex = tabPage.ordinal, - backgroundColor = backgroundColor, - indicator = { tabPositions -> - HomeTabIndicator(tabPositions, tabPage) + Column { + Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) + TabRow( + selectedTabIndex = tabPage.ordinal, + containerColor = backgroundColor, + contentColor = MaterialTheme.colorScheme.onPrimary, + indicator = { tabPositions -> + HomeTabIndicator(tabPositions, tabPage) + } + ) { + HomeTab( + icon = Icons.Default.Home, + title = stringResource(R.string.home), + onClick = { onTabSelected(TabPage.Home) } + ) + HomeTab( + icon = Icons.Default.AccountBox, + title = stringResource(R.string.work), + onClick = { onTabSelected(TabPage.Work) } + ) } - ) { - HomeTab( - icon = Icons.Default.Home, - title = stringResource(R.string.home), - onClick = { onTabSelected(TabPage.Home) } - ) - HomeTab( - icon = Icons.Default.AccountBox, - title = stringResource(R.string.work), - onClick = { onTabSelected(TabPage.Work) } - ) } } @@ -445,7 +460,7 @@ private fun HomeTabIndicator( // TODO 4: Animate these value changes. val indicatorLeft = tabPositions[tabPage.ordinal].left val indicatorRight = tabPositions[tabPage.ordinal].right - val color = if (tabPage == TabPage.Home) Purple700 else Green800 + val color = if (tabPage == TabPage.Home) PaleDogwood else Green Box( Modifier .fillMaxSize() @@ -566,7 +581,7 @@ private fun TaskRow(task: String, onRemove: () -> Unit) { modifier = Modifier .fillMaxWidth() .swipeToDismiss(onRemove), - elevation = 2.dp + shadowElevation = 2.dp ) { Row( modifier = Modifier @@ -580,7 +595,7 @@ private fun TaskRow(task: String, onRemove: () -> Unit) { Spacer(modifier = Modifier.width(16.dp)) Text( text = task, - style = MaterialTheme.typography.body1 + style = MaterialTheme.typography.bodySmall ) } } @@ -639,7 +654,7 @@ private fun Modifier.swipeToDismiss( @Composable private fun PreviewHomeTabBar() { HomeTabBar( - backgroundColor = Purple100, + backgroundColor = PaleDogwood, tabPage = TabPage.Home, onTabSelected = {} ) diff --git a/AnimationCodelab/start/src/main/res/values/themes.xml b/AnimationCodelab/start/src/main/res/values/themes.xml index 142395811..6af42df8e 100644 --- a/AnimationCodelab/start/src/main/res/values/themes.xml +++ b/AnimationCodelab/start/src/main/res/values/themes.xml @@ -16,7 +16,5 @@ --> diff --git a/README.md b/README.md index 58f992add..b6b0b7249 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ For more information about Jetpack Compose, please [read the documentation](http ## 💻 Requirements -[Android Studio Chipmunk](https://developer.android.com/studio). +[Latest version of Android Studio](https://developer.android.com/studio). ## 🧬 Codelabs From 0e584a5139ce38a5efdc4d46bdebfcab258a2e36 Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Mon, 20 Nov 2023 14:12:46 +0000 Subject: [PATCH 2/5] PR review fixes --- .../android/codelab/animation/ui/home/Home.kt | 37 +++++++-------- .../android/codelab/animation/ui/home/Home.kt | 45 ++++++++++++------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 17c185317..1cff879d6 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -184,7 +184,10 @@ fun Home() { val lazyListState = rememberLazyListState() // The background color. The value is changed by the current tab. - val backgroundColor by animateColorAsState(if (tabPage == TabPage.Home) Seashell else GreenLight) + val backgroundColor by animateColorAsState( + if (tabPage == TabPage.Home) Seashell else GreenLight, + label = "background color" + ) // The coroutine scope for event handlers calling suspend functions. val coroutineScope = rememberCoroutineScope() @@ -263,16 +266,11 @@ fun Home() { } } } - items(count = tasks.size) { i -> - val task = tasks.getOrNull(i) - if (task != null) { - key(task) { - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) - } - } + items(tasks, key = { it }) { task -> + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) } } EditMessage(editMessageShown) @@ -611,7 +609,7 @@ private fun WeatherRow( @Composable private fun LoadingRow() { // Creates an `InfiniteTransition` that runs infinite child animation values. - val infiniteTransition = rememberInfiniteTransition() + val infiniteTransition = rememberInfiniteTransition(label = "infinite loading") val alpha by infiniteTransition.animateFloat( initialValue = 0f, targetValue = 1f, @@ -627,7 +625,8 @@ private fun LoadingRow() { // When the value finishes animating from 0f to 1f, it repeats by reversing the // animation direction. repeatMode = RepeatMode.Reverse - ) + ), + label = "alpha" ) Row( modifier = Modifier @@ -750,11 +749,13 @@ private fun Modifier.swipeToDismiss( @Preview @Composable private fun PreviewHomeTabBar() { - HomeTabBar( - backgroundColor = PaleDogwood, - tabPage = TabPage.Home, - onTabSelected = {} - ) + AnimationCodelabTheme { + HomeTabBar( + backgroundColor = Color.White, + tabPage = TabPage.Home, + onTabSelected = {} + ) + } } @Preview diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 829dc78a6..f8e48bb64 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -17,6 +17,23 @@ package com.example.android.codelab.animation.ui.home import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.animateColor +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.animateContentSize +import androidx.compose.animation.core.FastOutLinearInEasing +import androidx.compose.animation.core.LinearOutSlowInEasing +import androidx.compose.animation.core.RepeatMode +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateDp +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.keyframes +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween +import androidx.compose.animation.core.updateTransition +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically import androidx.compose.animation.splineBasedDecay import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background @@ -85,6 +102,7 @@ import androidx.compose.ui.composed import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Color.Companion.White import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.positionChange @@ -243,16 +261,11 @@ fun Home() { } } } - items(count = tasks.size) { i -> - val task = tasks.getOrNull(i) - if (task != null) { - key(task) { - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) - } - } + items(tasks, key = { it }) { task -> + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) } } EditMessage(editMessageShown) @@ -653,11 +666,13 @@ private fun Modifier.swipeToDismiss( @Preview @Composable private fun PreviewHomeTabBar() { - HomeTabBar( - backgroundColor = PaleDogwood, - tabPage = TabPage.Home, - onTabSelected = {} - ) + AnimationCodelabTheme { + HomeTabBar( + backgroundColor = White, + tabPage = TabPage.Home, + onTabSelected = {} + ) + } } @Preview From 116b6a679b518476960af7f0248a5f00dfca9a48 Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Wed, 22 Nov 2023 11:58:04 +0000 Subject: [PATCH 3/5] PR review fixes --- .../android/codelab/animation/ui/home/Home.kt | 121 ++++++++--------- .../android/codelab/animation/ui/home/Home.kt | 127 +++++++++--------- 2 files changed, 126 insertions(+), 122 deletions(-) diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 1cff879d6..edf20dae7 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -51,6 +51,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -62,6 +63,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn @@ -115,6 +117,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.android.codelab.animation.R @@ -211,70 +214,69 @@ fun Home() { ) } ) { padding -> - Box(Modifier - .consumeWindowInsets( - WindowInsets.safeDrawing.only(WindowInsetsSides.Top) - ) - .padding(padding)) { - - LazyColumn( - contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp), - state = lazyListState - ) { - // Weather - item { Header(title = stringResource(R.string.weather)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - item { - Surface( - modifier = Modifier.fillMaxWidth(), - shadowElevation = 2.dp - ) { - if (weatherLoading) { - LoadingRow() - } else { - WeatherRow(onRefresh = { - coroutineScope.launch { - loadWeather() - } - }) - } + LazyColumn( + contentPadding = WindowInsets( + padding.calculateLeftPadding(LayoutDirection.Ltr) + 16.dp, + padding.calculateTopPadding() + 32.dp, + padding.calculateRightPadding(LayoutDirection.Ltr) + 16.dp, + padding.calculateBottomPadding() + 32.dp + ).asPaddingValues(), + state = lazyListState + ) { + // Weather + item { Header(title = stringResource(R.string.weather)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + item { + Surface( + modifier = Modifier.fillMaxWidth(), + shadowElevation = 2.dp + ) { + if (weatherLoading) { + LoadingRow() + } else { + WeatherRow(onRefresh = { + coroutineScope.launch { + loadWeather() + } + }) } } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Topics - item { Header(title = stringResource(R.string.topics)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - items(allTopics) { topic -> - TopicRow( - topic = topic, - expanded = expandedTopic == topic, - onClick = { - expandedTopic = if (expandedTopic == topic) null else topic - } - ) - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Tasks - item { Header(title = stringResource(R.string.tasks)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - if (tasks.isEmpty()) { - item { - TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { - Text(stringResource(R.string.add_tasks)) - } + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Topics + item { Header(title = stringResource(R.string.topics)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + items(allTopics) { topic -> + TopicRow( + topic = topic, + expanded = expandedTopic == topic, + onClick = { + expandedTopic = if (expandedTopic == topic) null else topic + } + ) + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Tasks + item { Header(title = stringResource(R.string.tasks)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + if (tasks.isEmpty()) { + item { + TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { + Text(stringResource(R.string.add_tasks)) } } - items(tasks, key = { it }) { task -> - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) - } } - EditMessage(editMessageShown) + items(tasks, key = { it }) { task -> + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) + } } + EditMessage(editMessageShown) + } } @@ -448,8 +450,7 @@ private fun HomeTabBar( tabPage: TabPage, onTabSelected: (tabPage: TabPage) -> Unit ) { - Column { - Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) + Column(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top))) { TabRow( selectedTabIndex = tabPage.ordinal, containerColor = backgroundColor, diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index f8e48bb64..8dcd5bafc 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -49,6 +49,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.WindowInsetsSides.Companion.Horizontal +import androidx.compose.foundation.layout.WindowInsetsSides.Companion.Top +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -59,7 +62,9 @@ import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn @@ -114,6 +119,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.android.codelab.animation.R @@ -206,70 +212,68 @@ fun Home() { ) } ) { padding -> - Box(Modifier - .consumeWindowInsets( - WindowInsets.safeDrawing.only(WindowInsetsSides.Top) - ) - .padding(padding)) { - - LazyColumn( - contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp), - state = lazyListState - ) { - // Weather - item { Header(title = stringResource(R.string.weather)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - item { - Surface( - modifier = Modifier.fillMaxWidth(), - shadowElevation = 2.dp - ) { - if (weatherLoading) { - LoadingRow() - } else { - WeatherRow(onRefresh = { - coroutineScope.launch { - loadWeather() - } - }) - } + LazyColumn( + contentPadding = WindowInsets( + padding.calculateLeftPadding(LayoutDirection.Ltr) + 16.dp, + padding.calculateTopPadding() + 32.dp, + padding.calculateRightPadding(LayoutDirection.Ltr) + 16.dp, + padding.calculateBottomPadding() + 32.dp + ).asPaddingValues(), + state = lazyListState + ) { + // Weather + item { Header(title = stringResource(R.string.weather)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + item { + Surface( + modifier = Modifier.fillMaxWidth(), + shadowElevation = 2.dp + ) { + if (weatherLoading) { + LoadingRow() + } else { + WeatherRow(onRefresh = { + coroutineScope.launch { + loadWeather() + } + }) } } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Topics - item { Header(title = stringResource(R.string.topics)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - items(allTopics) { topic -> - TopicRow( - topic = topic, - expanded = expandedTopic == topic, - onClick = { - expandedTopic = if (expandedTopic == topic) null else topic - } - ) - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Tasks - item { Header(title = stringResource(R.string.tasks)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - if (tasks.isEmpty()) { - item { - TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { - Text(stringResource(R.string.add_tasks)) - } + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Topics + item { Header(title = stringResource(R.string.topics)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + items(allTopics) { topic -> + TopicRow( + topic = topic, + expanded = expandedTopic == topic, + onClick = { + expandedTopic = if (expandedTopic == topic) null else topic + } + ) + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Tasks + item { Header(title = stringResource(R.string.tasks)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + if (tasks.isEmpty()) { + item { + TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { + Text(stringResource(R.string.add_tasks)) } - } - items(tasks, key = { it }) { task -> - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) } } - EditMessage(editMessageShown) + items(tasks, key = { it }) { task -> + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) + } } + EditMessage(editMessageShown) } } @@ -435,16 +439,15 @@ private fun HomeTabBar( tabPage: TabPage, onTabSelected: (tabPage: TabPage) -> Unit ) { - Column { - Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) + Column(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(Horizontal + Top)),) { TabRow( selectedTabIndex = tabPage.ordinal, - containerColor = backgroundColor, + containerColor = Color.Transparent, contentColor = MaterialTheme.colorScheme.onPrimary, indicator = { tabPositions -> HomeTabIndicator(tabPositions, tabPage) } - ) { + ){ HomeTab( icon = Icons.Default.Home, title = stringResource(R.string.home), From 9f84afb7d40897ad84d8169e6190af4b982041c2 Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Wed, 22 Nov 2023 12:08:57 +0000 Subject: [PATCH 4/5] PR review fixes --- .../android/codelab/animation/ui/Theme.kt | 3 +- .../android/codelab/animation/ui/home/Home.kt | 118 ++++++++--------- .../android/codelab/animation/ui/Theme.kt | 3 +- .../android/codelab/animation/ui/home/Home.kt | 119 +++++++++--------- 4 files changed, 128 insertions(+), 115 deletions(-) diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt index b1c5e4735..a46656ec5 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/Theme.kt @@ -27,7 +27,8 @@ fun AnimationCodelabTheme(content: @Composable () -> Unit) { primary = Melon, primaryContainer = PaleDogwood, onPrimary = Color.Black, - secondary = Peach + secondary = Peach, + onSecondary = Color.Black ) MaterialTheme( colorScheme = colors, diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index edf20dae7..3fbd1d358 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -52,6 +52,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -214,69 +215,71 @@ fun Home() { ) } ) { padding -> - LazyColumn( - contentPadding = WindowInsets( - padding.calculateLeftPadding(LayoutDirection.Ltr) + 16.dp, - padding.calculateTopPadding() + 32.dp, - padding.calculateRightPadding(LayoutDirection.Ltr) + 16.dp, - padding.calculateBottomPadding() + 32.dp - ).asPaddingValues(), - state = lazyListState - ) { - // Weather - item { Header(title = stringResource(R.string.weather)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - item { - Surface( - modifier = Modifier.fillMaxWidth(), - shadowElevation = 2.dp - ) { - if (weatherLoading) { - LoadingRow() - } else { - WeatherRow(onRefresh = { - coroutineScope.launch { - loadWeather() - } - }) + Box(modifier = Modifier.padding( + top = padding.calculateTopPadding(), + start = padding.calculateLeftPadding(LayoutDirection.Ltr), + end = padding.calculateEndPadding(LayoutDirection.Ltr) + )) { + LazyColumn( + contentPadding = WindowInsets(16.dp, 32.dp, 16.dp, + padding.calculateBottomPadding() + 32.dp + ).asPaddingValues(), + state = lazyListState + ) { + // Weather + item { Header(title = stringResource(R.string.weather)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + item { + Surface( + modifier = Modifier.fillMaxWidth(), + shadowElevation = 2.dp + ) { + if (weatherLoading) { + LoadingRow() + } else { + WeatherRow(onRefresh = { + coroutineScope.launch { + loadWeather() + } + }) + } } } - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Topics - item { Header(title = stringResource(R.string.topics)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - items(allTopics) { topic -> - TopicRow( - topic = topic, - expanded = expandedTopic == topic, - onClick = { - expandedTopic = if (expandedTopic == topic) null else topic - } - ) - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Tasks - item { Header(title = stringResource(R.string.tasks)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - if (tasks.isEmpty()) { - item { - TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { - Text(stringResource(R.string.add_tasks)) + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Topics + item { Header(title = stringResource(R.string.topics)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + items(allTopics) { topic -> + TopicRow( + topic = topic, + expanded = expandedTopic == topic, + onClick = { + expandedTopic = if (expandedTopic == topic) null else topic + } + ) + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Tasks + item { Header(title = stringResource(R.string.tasks)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + if (tasks.isEmpty()) { + item { + TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { + Text(stringResource(R.string.add_tasks)) + } } } + items(tasks, key = { it }) { task -> + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) + } } - items(tasks, key = { it }) { task -> - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) - } + EditMessage(editMessageShown) } - EditMessage(editMessageShown) - } } @@ -338,6 +341,7 @@ private fun EditMessage(shown: Boolean) { ) { Text( text = stringResource(R.string.edit_message), + color = MaterialTheme.colorScheme.onSecondary, modifier = Modifier.padding(16.dp) ) } diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt index a1ca1410c..46d7cd068 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/Theme.kt @@ -27,7 +27,8 @@ fun AnimationCodelabTheme(content: @Composable () -> Unit) { primary = Melon, primaryContainer = PaleDogwood, onPrimary = Color.Black, - secondary = Peach + secondary = Peach, + onSecondary = Color.Black ) MaterialTheme( colorScheme = colors, diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 8dcd5bafc..3a3cc40d0 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -52,6 +52,7 @@ import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.WindowInsetsSides.Companion.Horizontal import androidx.compose.foundation.layout.WindowInsetsSides.Companion.Top import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -212,68 +213,74 @@ fun Home() { ) } ) { padding -> - LazyColumn( - contentPadding = WindowInsets( - padding.calculateLeftPadding(LayoutDirection.Ltr) + 16.dp, - padding.calculateTopPadding() + 32.dp, - padding.calculateRightPadding(LayoutDirection.Ltr) + 16.dp, - padding.calculateBottomPadding() + 32.dp - ).asPaddingValues(), - state = lazyListState - ) { - // Weather - item { Header(title = stringResource(R.string.weather)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - item { - Surface( - modifier = Modifier.fillMaxWidth(), - shadowElevation = 2.dp - ) { - if (weatherLoading) { - LoadingRow() - } else { - WeatherRow(onRefresh = { - coroutineScope.launch { - loadWeather() - } - }) + Box(modifier = Modifier.padding( + top = padding.calculateTopPadding(), + start = padding.calculateLeftPadding(LayoutDirection.Ltr), + end = padding.calculateEndPadding(LayoutDirection.Ltr) + )) { + LazyColumn( + contentPadding = WindowInsets( + 16.dp, + 32.dp, + 16.dp, + padding.calculateBottomPadding() + 32.dp + ).asPaddingValues(), + state = lazyListState + ) { + // Weather + item { Header(title = stringResource(R.string.weather)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + item { + Surface( + modifier = Modifier.fillMaxWidth(), + shadowElevation = 2.dp + ) { + if (weatherLoading) { + LoadingRow() + } else { + WeatherRow(onRefresh = { + coroutineScope.launch { + loadWeather() + } + }) + } } } - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Topics - item { Header(title = stringResource(R.string.topics)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - items(allTopics) { topic -> - TopicRow( - topic = topic, - expanded = expandedTopic == topic, - onClick = { - expandedTopic = if (expandedTopic == topic) null else topic - } - ) - } - item { Spacer(modifier = Modifier.height(32.dp)) } - - // Tasks - item { Header(title = stringResource(R.string.tasks)) } - item { Spacer(modifier = Modifier.height(16.dp)) } - if (tasks.isEmpty()) { - item { - TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { - Text(stringResource(R.string.add_tasks)) + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Topics + item { Header(title = stringResource(R.string.topics)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + items(allTopics) { topic -> + TopicRow( + topic = topic, + expanded = expandedTopic == topic, + onClick = { + expandedTopic = if (expandedTopic == topic) null else topic + } + ) + } + item { Spacer(modifier = Modifier.height(32.dp)) } + + // Tasks + item { Header(title = stringResource(R.string.tasks)) } + item { Spacer(modifier = Modifier.height(16.dp)) } + if (tasks.isEmpty()) { + item { + TextButton(onClick = { tasks.clear(); tasks.addAll(allTasks) }) { + Text(stringResource(R.string.add_tasks)) + } } } + items(tasks, key = { it }) { task -> + TaskRow( + task = task, + onRemove = { tasks.remove(task) } + ) + } } - items(tasks, key = { it }) { task -> - TaskRow( - task = task, - onRemove = { tasks.remove(task) } - ) - } + EditMessage(editMessageShown) } - EditMessage(editMessageShown) } } From 9d584455fd9757942d4ea1782fbea95feaf73273 Mon Sep 17 00:00:00 2001 From: Rebecca Franks Date: Thu, 23 Nov 2023 10:36:44 +0000 Subject: [PATCH 5/5] PR review fixes --- .../com/example/android/codelab/animation/ui/home/Home.kt | 3 ++- .../com/example/android/codelab/animation/ui/home/Home.kt | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 3fbd1d358..ec194df17 100644 --- a/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/finished/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -454,7 +454,8 @@ private fun HomeTabBar( tabPage: TabPage, onTabSelected: (tabPage: TabPage) -> Unit ) { - Column(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top))) { + Column(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal))) { + Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) TabRow( selectedTabIndex = tabPage.ordinal, containerColor = backgroundColor, diff --git a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt index 3a3cc40d0..0ea248583 100644 --- a/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt +++ b/AnimationCodelab/start/src/main/java/com/example/android/codelab/animation/ui/home/Home.kt @@ -446,10 +446,11 @@ private fun HomeTabBar( tabPage: TabPage, onTabSelected: (tabPage: TabPage) -> Unit ) { - Column(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(Horizontal + Top)),) { + Column(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(Horizontal))) { + Spacer(Modifier.windowInsetsTopHeight(WindowInsets.safeDrawing)) TabRow( selectedTabIndex = tabPage.ordinal, - containerColor = Color.Transparent, + containerColor = backgroundColor, contentColor = MaterialTheme.colorScheme.onPrimary, indicator = { tabPositions -> HomeTabIndicator(tabPositions, tabPage)