diff --git a/app-nia-catalog/src/main/java/com/google/samples/apps/niacatalog/ui/Catalog.kt b/app-nia-catalog/src/main/java/com/google/samples/apps/niacatalog/ui/Catalog.kt index 851c20b28..965d03c47 100644 --- a/app-nia-catalog/src/main/java/com/google/samples/apps/niacatalog/ui/Catalog.kt +++ b/app-nia-catalog/src/main/java/com/google/samples/apps/niacatalog/ui/Catalog.kt @@ -37,16 +37,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.google.accompanist.flowlayout.FlowRow +import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaDropdownMenuButton -import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilledButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip +import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationBar import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaNavigationBarItem import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaOutlinedButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTab import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTabRow import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTextButton -import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaViewToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons @@ -77,7 +77,7 @@ fun NiaCatalog() { item { Text("Buttons", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton(onClick = {}) { + NiaButton(onClick = {}) { Text(text = "Enabled") } NiaOutlinedButton(onClick = {}) { @@ -91,7 +91,7 @@ fun NiaCatalog() { item { Text("Disabled buttons", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( + NiaButton( onClick = {}, enabled = false ) { @@ -114,7 +114,7 @@ fun NiaCatalog() { item { Text("Buttons with leading icons", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( + NiaButton( onClick = {}, text = { Text(text = "Enabled") }, leadingIcon = { @@ -140,7 +140,7 @@ fun NiaCatalog() { item { Text("Disabled buttons with leading icons", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( + NiaButton( onClick = {}, enabled = false, text = { Text(text = "Disabled") }, @@ -166,251 +166,24 @@ fun NiaCatalog() { ) } } - item { Text("Buttons with trailing icons", Modifier.padding(top = 16.dp)) } + item { Text("Dropdown menus", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - text = { Text(text = "Enabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaOutlinedButton( - onClick = {}, - text = { Text(text = "Enabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaTextButton( - onClick = {}, - text = { Text(text = "Enabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - } - } - item { Text("Disabled buttons with trailing icons", Modifier.padding(top = 16.dp)) } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - enabled = false, - text = { Text(text = "Disabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaOutlinedButton( - onClick = {}, - enabled = false, - text = { Text(text = "Disabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaTextButton( - onClick = {}, - enabled = false, - text = { Text(text = "Disabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - } - } - item { Text("Small buttons", Modifier.padding(top = 16.dp)) } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - small = true - ) { - Text(text = "Enabled") - } - NiaOutlinedButton( - onClick = {}, - small = true - ) { - Text(text = "Enabled") - } - NiaTextButton( - onClick = {}, - small = true - ) { - Text(text = "Enabled") - } - } - } - item { Text("Disabled small buttons", Modifier.padding(top = 16.dp)) } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - enabled = false, - small = true - ) { - Text(text = "Disabled") - } - NiaOutlinedButton( - onClick = {}, - enabled = false, - small = true - ) { - Text(text = "Disabled") - } - NiaTextButton( - onClick = {}, - enabled = false, - small = true - ) { - Text(text = "Disabled") - } - } - } - item { Text("Small buttons with leading icons", Modifier.padding(top = 16.dp)) } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - small = true, - text = { Text(text = "Enabled") }, - leadingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaOutlinedButton( - onClick = {}, - small = true, - text = { Text(text = "Enabled") }, - leadingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaTextButton( - onClick = {}, - small = true, - text = { Text(text = "Enabled") }, - leadingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - } - } - item { - Text( - "Disabled small buttons with leading icons", - Modifier.padding(top = 16.dp) - ) - } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - enabled = false, - small = true, - text = { Text(text = "Disabled") }, - leadingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaOutlinedButton( - onClick = {}, - enabled = false, - small = true, - text = { Text(text = "Disabled") }, - leadingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaTextButton( - onClick = {}, - enabled = false, - small = true, - text = { Text(text = "Disabled") }, - leadingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - } - } - item { Text("Small buttons with trailing icons", Modifier.padding(top = 16.dp)) } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - small = true, - text = { Text(text = "Enabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaOutlinedButton( - onClick = {}, - small = true, - text = { Text(text = "Enabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaTextButton( - onClick = {}, - small = true, - text = { Text(text = "Enabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - } - } - item { - Text( - "Disabled small buttons with trailing icons", - Modifier.padding(top = 16.dp) - ) - } - item { - FlowRow(mainAxisSpacing = 16.dp) { - NiaFilledButton( - onClick = {}, - enabled = false, - small = true, - text = { Text(text = "Disabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaOutlinedButton( - onClick = {}, - enabled = false, - small = true, - text = { Text(text = "Disabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } - ) - NiaTextButton( - onClick = {}, - enabled = false, - small = true, - text = { Text(text = "Disabled") }, - trailingIcon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) - } + NiaDropdownMenuButton( + text = { Text("Enabled") }, + items = listOf("Item 1", "Item 2", "Item 3"), + onItemClick = {}, + itemText = { item -> Text(item) } + ) + NiaDropdownMenuButton( + text = { Text("Disabled") }, + items = listOf("Item 1", "Item 2", "Item 3"), + onItemClick = {}, + itemText = { item -> Text(item) }, + enabled = false ) } } - item { Text("Dropdown menu", Modifier.padding(top = 16.dp)) } - item { - NiaDropdownMenuButton( - text = { Text("Newest first") }, - items = listOf("Item 1", "Item 2", "Item 3"), - onItemClick = {}, - itemText = { item -> Text(item) } - ) - } item { Text("Chips", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { @@ -418,28 +191,33 @@ fun NiaCatalog() { NiaFilterChip( selected = firstChecked, onSelectedChange = { checked -> firstChecked = checked }, - label = { Text(text = "Enabled".uppercase()) } + label = { Text(text = "Enabled") } ) var secondChecked by remember { mutableStateOf(true) } NiaFilterChip( selected = secondChecked, onSelectedChange = { checked -> secondChecked = checked }, - label = { Text(text = "Enabled".uppercase()) } + label = { Text(text = "Enabled") } ) - var thirdChecked by remember { mutableStateOf(true) } NiaFilterChip( - selected = thirdChecked, - onSelectedChange = { checked -> thirdChecked = checked }, + selected = false, + onSelectedChange = {}, enabled = false, - label = { Text(text = "Disabled".uppercase()) } + label = { Text(text = "Disabled") } + ) + NiaFilterChip( + selected = true, + onSelectedChange = {}, + enabled = false, + label = { Text(text = "Disabled") } ) } } - item { Text("Toggle buttons", Modifier.padding(top = 16.dp)) } + item { Text("Icon buttons", Modifier.padding(top = 16.dp)) } item { FlowRow(mainAxisSpacing = 16.dp) { var firstChecked by remember { mutableStateOf(false) } - NiaToggleButton( + NiaIconToggleButton( checked = firstChecked, onCheckedChange = { checked -> firstChecked = checked }, icon = { @@ -456,7 +234,7 @@ fun NiaCatalog() { } ) var secondChecked by remember { mutableStateOf(true) } - NiaToggleButton( + NiaIconToggleButton( checked = secondChecked, onCheckedChange = { checked -> secondChecked = checked }, icon = { @@ -472,27 +250,39 @@ fun NiaCatalog() { ) } ) - var thirdChecked by remember { mutableStateOf(false) } - NiaToggleButton( - checked = thirdChecked, - onCheckedChange = { checked -> thirdChecked = checked }, + NiaIconToggleButton( + checked = false, + onCheckedChange = {}, icon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) + Icon( + painter = painterResource(id = NiaIcons.BookmarkBorder), + contentDescription = null + ) }, checkedIcon = { - Icon(imageVector = NiaIcons.Check, contentDescription = null) - } + Icon( + painter = painterResource(id = NiaIcons.Bookmark), + contentDescription = null + ) + }, + enabled = false ) - var fourthChecked by remember { mutableStateOf(true) } - NiaToggleButton( - checked = fourthChecked, - onCheckedChange = { checked -> fourthChecked = checked }, + NiaIconToggleButton( + checked = true, + onCheckedChange = {}, icon = { - Icon(imageVector = NiaIcons.Add, contentDescription = null) + Icon( + painter = painterResource(id = NiaIcons.BookmarkBorder), + contentDescription = null + ) }, checkedIcon = { - Icon(imageVector = NiaIcons.Check, contentDescription = null) - } + Icon( + painter = painterResource(id = NiaIcons.Bookmark), + contentDescription = null + ) + }, + enabled = false ) } } @@ -513,6 +303,13 @@ fun NiaCatalog() { compactText = { Text(text = "Compact view") }, expandedText = { Text(text = "Expanded view") } ) + NiaViewToggleButton( + expanded = false, + onExpandedChange = {}, + compactText = { Text(text = "Disabled") }, + expandedText = { Text(text = "Disabled") }, + enabled = false + ) } } item { Text("Tags", Modifier.padding(top = 16.dp)) } @@ -524,7 +321,7 @@ fun NiaCatalog() { NiaTopicTag( expanded = expandedTopicId == "Topic 1", followed = firstFollowed, - onDropMenuToggle = { show -> + onDropdownMenuToggle = { show -> expandedTopicId = if (show) "Topic 1" else null }, onFollowClick = { firstFollowed = true }, @@ -539,7 +336,7 @@ fun NiaCatalog() { NiaTopicTag( expanded = expandedTopicId == "Topic 2", followed = secondFollowed, - onDropMenuToggle = { show -> + onDropdownMenuToggle = { show -> expandedTopicId = if (show) "Topic 2" else null }, onFollowClick = { secondFollowed = true }, @@ -550,6 +347,16 @@ fun NiaCatalog() { unFollowText = { Text(text = "Unfollow") }, browseText = { Text(text = "Browse topic") } ) + NiaTopicTag( + expanded = false, + followed = false, + onDropdownMenuToggle = {}, + onFollowClick = {}, + onUnfollowClick = {}, + onBrowseClick = {}, + text = { Text(text = "Disabled".uppercase()) }, + enabled = false + ) } } item { Text("Tabs", Modifier.padding(top = 16.dp)) } diff --git a/core/designsystem/src/androidTest/java/com/google/samples/apps/nowinandroid/core/designsystem/ThemeTest.kt b/core/designsystem/src/androidTest/java/com/google/samples/apps/nowinandroid/core/designsystem/ThemeTest.kt index 4bc69712d..e97762318 100644 --- a/core/designsystem/src/androidTest/java/com/google/samples/apps/nowinandroid/core/designsystem/ThemeTest.kt +++ b/core/designsystem/src/androidTest/java/com/google/samples/apps/nowinandroid/core/designsystem/ThemeTest.kt @@ -21,6 +21,7 @@ import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.unit.dp @@ -32,7 +33,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColo import com.google.samples.apps.nowinandroid.core.designsystem.theme.LightAndroidBackgroundTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.LightAndroidColorScheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.LightDefaultColorScheme -import com.google.samples.apps.nowinandroid.core.designsystem.theme.LightDefaultGradientColors import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalBackgroundTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme @@ -63,12 +63,9 @@ class ThemeTest { ) { val colorScheme = LightDefaultColorScheme assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = LightDefaultGradientColors + val gradientColors = defaultGradientColors(colorScheme) assertEquals(gradientColors, LocalGradientColors.current) - val backgroundTheme = BackgroundTheme( - color = colorScheme.surface, - tonalElevation = 2.dp - ) + val backgroundTheme = defaultBackgroundTheme(colorScheme) assertEquals(backgroundTheme, LocalBackgroundTheme.current) } } @@ -84,12 +81,9 @@ class ThemeTest { ) { val colorScheme = DarkDefaultColorScheme assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = GradientColors() + val gradientColors = defaultGradientColors(colorScheme) assertEquals(gradientColors, LocalGradientColors.current) - val backgroundTheme = BackgroundTheme( - color = colorScheme.surface, - tonalElevation = 2.dp - ) + val backgroundTheme = defaultBackgroundTheme(colorScheme) assertEquals(backgroundTheme, LocalBackgroundTheme.current) } } @@ -102,22 +96,11 @@ class ThemeTest { darkTheme = false, androidTheme = false ) { - val colorScheme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - dynamicLightColorScheme(LocalContext.current) - } else { - LightDefaultColorScheme - } + val colorScheme = dynamicLightColorSchemeWithFallback() assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - GradientColors() - } else { - LightDefaultGradientColors - } + val gradientColors = dynamicGradientColorsWithFallback(colorScheme) assertEquals(gradientColors, LocalGradientColors.current) - val backgroundTheme = BackgroundTheme( - color = colorScheme.surface, - tonalElevation = 2.dp - ) + val backgroundTheme = defaultBackgroundTheme(colorScheme) assertEquals(backgroundTheme, LocalBackgroundTheme.current) } } @@ -130,18 +113,11 @@ class ThemeTest { darkTheme = true, androidTheme = false ) { - val colorScheme = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - dynamicDarkColorScheme(LocalContext.current) - } else { - DarkDefaultColorScheme - } + val colorScheme = dynamicDarkColorSchemeWithFallback() assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = GradientColors() + val gradientColors = dynamicGradientColorsWithFallback(colorScheme) assertEquals(gradientColors, LocalGradientColors.current) - val backgroundTheme = BackgroundTheme( - color = colorScheme.surface, - tonalElevation = 2.dp - ) + val backgroundTheme = defaultBackgroundTheme(colorScheme) assertEquals(backgroundTheme, LocalBackgroundTheme.current) } } @@ -157,7 +133,7 @@ class ThemeTest { ) { val colorScheme = LightAndroidColorScheme assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = GradientColors() + val gradientColors = emptyGradientColors assertEquals(gradientColors, LocalGradientColors.current) val backgroundTheme = LightAndroidBackgroundTheme assertEquals(backgroundTheme, LocalBackgroundTheme.current) @@ -175,7 +151,7 @@ class ThemeTest { ) { val colorScheme = DarkAndroidColorScheme assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = GradientColors() + val gradientColors = emptyGradientColors assertEquals(gradientColors, LocalGradientColors.current) val backgroundTheme = DarkAndroidBackgroundTheme assertEquals(backgroundTheme, LocalBackgroundTheme.current) @@ -190,11 +166,11 @@ class ThemeTest { darkTheme = false, androidTheme = true ) { - val colorScheme = LightAndroidColorScheme + val colorScheme = dynamicLightColorSchemeWithFallback() assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = GradientColors() + val gradientColors = dynamicGradientColorsWithFallback(colorScheme) assertEquals(gradientColors, LocalGradientColors.current) - val backgroundTheme = LightAndroidBackgroundTheme + val backgroundTheme = defaultBackgroundTheme(colorScheme) assertEquals(backgroundTheme, LocalBackgroundTheme.current) } } @@ -207,16 +183,59 @@ class ThemeTest { darkTheme = true, androidTheme = true ) { - val colorScheme = DarkAndroidColorScheme + val colorScheme = dynamicDarkColorSchemeWithFallback() assertColorSchemesEqual(colorScheme, MaterialTheme.colorScheme) - val gradientColors = GradientColors() + val gradientColors = dynamicGradientColorsWithFallback(colorScheme) assertEquals(gradientColors, LocalGradientColors.current) - val backgroundTheme = DarkAndroidBackgroundTheme + val backgroundTheme = defaultBackgroundTheme(colorScheme) assertEquals(backgroundTheme, LocalBackgroundTheme.current) } } } + @Composable + private fun dynamicLightColorSchemeWithFallback(): ColorScheme { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + dynamicLightColorScheme(LocalContext.current) + } else { + LightDefaultColorScheme + } + } + + @Composable + private fun dynamicDarkColorSchemeWithFallback(): ColorScheme { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + dynamicDarkColorScheme(LocalContext.current) + } else { + DarkDefaultColorScheme + } + } + + private val emptyGradientColors = GradientColors() + + private fun defaultGradientColors(colorScheme: ColorScheme): GradientColors { + return GradientColors( + top = colorScheme.inverseOnSurface, + bottom = colorScheme.primaryContainer, + container = colorScheme.surface + ) + } + + private fun dynamicGradientColorsWithFallback(colorScheme: ColorScheme): GradientColors { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + emptyGradientColors + } else { + defaultGradientColors(colorScheme) + } + } + + private fun defaultBackgroundTheme(colorScheme: ColorScheme): BackgroundTheme { + return BackgroundTheme( + color = colorScheme.surface, + tonalElevation = 2.dp + ) + } + /** * Workaround for the fact that the NiA design system specify all color scheme values. */ @@ -249,6 +268,8 @@ class ThemeTest { assertEquals(expectedColorScheme.onSurface, actualColorScheme.onSurface) assertEquals(expectedColorScheme.surfaceVariant, actualColorScheme.surfaceVariant) assertEquals(expectedColorScheme.onSurfaceVariant, actualColorScheme.onSurfaceVariant) + assertEquals(expectedColorScheme.inverseSurface, actualColorScheme.inverseSurface) + assertEquals(expectedColorScheme.inverseOnSurface, actualColorScheme.inverseOnSurface) assertEquals(expectedColorScheme.outline, actualColorScheme.outline) } } diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Background.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Background.kt index 833ec955d..6eb818011 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Background.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Background.kt @@ -41,7 +41,7 @@ import kotlin.math.tan /** * The main background for the app. - * Uses [LocalBackgroundTheme] to set the color and tonal elevation of a [Box]. + * Uses [LocalBackgroundTheme] to set the color and tonal elevation of a [Surface]. * * @param modifier Modifier to be applied to the background. * @param content The background content. @@ -66,23 +66,28 @@ fun NiaBackground( /** * A gradient background for select screens. Uses [LocalBackgroundTheme] to set the gradient colors - * of a [Box]. + * of a [Box] within a [Surface]. * * @param modifier Modifier to be applied to the background. * @param topColor The top gradient color to be rendered. * @param bottomColor The bottom gradient color to be rendered. + * @param containerColor The container color over which the gradient will be rendered. * @param content The background content. */ @Composable fun NiaGradientBackground( modifier: Modifier = Modifier, - topColor: Color = LocalGradientColors.current.primary, - bottomColor: Color = LocalGradientColors.current.secondary, + topColor: Color = LocalGradientColors.current.top, + bottomColor: Color = LocalGradientColors.current.bottom, + containerColor: Color = LocalGradientColors.current.container, content: @Composable () -> Unit ) { val currentTopColor by rememberUpdatedState(topColor) val currentBottomColor by rememberUpdatedState(bottomColor) - NiaBackground(modifier) { + Surface( + color = if (containerColor == Color.Unspecified) Color.Transparent else containerColor, + modifier = modifier.fillMaxSize() + ) { Box( Modifier .fillMaxSize() diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Button.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Button.kt index 149f1ccbc..cab6fcd2f 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Button.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Button.kt @@ -20,20 +20,15 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.sizeIn import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp /** @@ -43,38 +38,27 @@ import androidx.compose.ui.unit.dp * @param modifier Modifier to be applied to the button. * @param enabled Controls the enabled state of the button. When `false`, this button will not be * clickable and will appear disabled to accessibility services. - * @param small Whether or not the size of the button should be small or regular. - * @param colors [ButtonColors] that will be used to resolve the container and content color for - * this button in different states. See [NiaButtonDefaults.filledButtonColors]. * @param contentPadding The spacing values to apply internally between the container and the - * content. See [NiaButtonDefaults.buttonContentPadding]. + * content. * @param content The button content. */ @Composable -fun NiaFilledButton( +fun NiaButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - small: Boolean = false, - colors: ButtonColors = NiaButtonDefaults.filledButtonColors(), - contentPadding: PaddingValues = NiaButtonDefaults.buttonContentPadding(small = small), + contentPadding: PaddingValues = ButtonDefaults.ContentPadding, content: @Composable RowScope.() -> Unit ) { Button( onClick = onClick, - modifier = if (small) { - modifier.heightIn(min = NiaButtonDefaults.SmallButtonHeight) - } else { - modifier - }, + modifier = modifier, enabled = enabled, - colors = colors, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.onBackground + ), contentPadding = contentPadding, - content = { - ProvideTextStyle(value = MaterialTheme.typography.labelSmall) { - content() - } - } + content = content ) } @@ -85,40 +69,30 @@ fun NiaFilledButton( * @param modifier Modifier to be applied to the button. * @param enabled Controls the enabled state of the button. When `false`, this button will not be * clickable and will appear disabled to accessibility services. - * @param small Whether or not the size of the button should be small or regular. - * @param colors [ButtonColors] that will be used to resolve the container and content color for - * this button in different states. See [NiaButtonDefaults.filledButtonColors]. * @param text The button text label content. * @param leadingIcon The button leading icon content. Pass `null` here for no leading icon. - * @param trailingIcon The button trailing icon content. Pass `null` here for no trailing icon. */ @Composable -fun NiaFilledButton( +fun NiaButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - small: Boolean = false, - colors: ButtonColors = NiaButtonDefaults.filledButtonColors(), text: @Composable () -> Unit, - leadingIcon: @Composable (() -> Unit)? = null, - trailingIcon: @Composable (() -> Unit)? = null + leadingIcon: @Composable (() -> Unit)? = null ) { - NiaFilledButton( + NiaButton( onClick = onClick, modifier = modifier, enabled = enabled, - small = small, - colors = colors, - contentPadding = NiaButtonDefaults.buttonContentPadding( - small = small, - leadingIcon = leadingIcon != null, - trailingIcon = trailingIcon != null - ) + contentPadding = if (leadingIcon != null) { + ButtonDefaults.ButtonWithIconContentPadding + } else { + ButtonDefaults.ContentPadding + } ) { NiaButtonContent( text = text, - leadingIcon = leadingIcon, - trailingIcon = trailingIcon + leadingIcon = leadingIcon ) } } @@ -130,12 +104,8 @@ fun NiaFilledButton( * @param modifier Modifier to be applied to the button. * @param enabled Controls the enabled state of the button. When `false`, this button will not be * clickable and will appear disabled to accessibility services. - * @param small Whether or not the size of the button should be small or regular. - * @param border Border to draw around the button. Pass `null` here for no border. - * @param colors [ButtonColors] that will be used to resolve the container and content color for - * this button in different states. See [NiaButtonDefaults.outlinedButtonColors]. * @param contentPadding The spacing values to apply internally between the container and the - * content. See [NiaButtonDefaults.buttonContentPadding]. + * content. * @param content The button content. */ @Composable @@ -143,28 +113,28 @@ fun NiaOutlinedButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - small: Boolean = false, - border: BorderStroke? = NiaButtonDefaults.outlinedButtonBorder(enabled = enabled), - colors: ButtonColors = NiaButtonDefaults.outlinedButtonColors(), - contentPadding: PaddingValues = NiaButtonDefaults.buttonContentPadding(small = small), + contentPadding: PaddingValues = ButtonDefaults.ContentPadding, content: @Composable RowScope.() -> Unit ) { OutlinedButton( onClick = onClick, - modifier = if (small) { - modifier.heightIn(min = NiaButtonDefaults.SmallButtonHeight) - } else { - modifier - }, + modifier = modifier, enabled = enabled, - border = border, - colors = colors, - contentPadding = contentPadding, - content = { - ProvideTextStyle(value = MaterialTheme.typography.labelSmall) { - content() + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.onBackground + ), + border = BorderStroke( + width = NiaButtonDefaults.OutlinedButtonBorderWidth, + color = if (enabled) { + MaterialTheme.colorScheme.outline + } else { + MaterialTheme.colorScheme.onSurface.copy( + alpha = NiaButtonDefaults.DisabledOutlinedButtonBorderAlpha + ) } - } + ), + contentPadding = contentPadding, + content = content ) } @@ -175,43 +145,30 @@ fun NiaOutlinedButton( * @param modifier Modifier to be applied to the button. * @param enabled Controls the enabled state of the button. When `false`, this button will not be * clickable and will appear disabled to accessibility services. - * @param small Whether or not the size of the button should be small or regular. - * @param border Border to draw around the button. Pass `null` here for no border. - * @param colors [ButtonColors] that will be used to resolve the container and content color for - * this button in different states. See [NiaButtonDefaults.outlinedButtonColors]. * @param text The button text label content. * @param leadingIcon The button leading icon content. Pass `null` here for no leading icon. - * @param trailingIcon The button trailing icon content. Pass `null` here for no trailing icon. */ @Composable fun NiaOutlinedButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - small: Boolean = false, - border: BorderStroke? = NiaButtonDefaults.outlinedButtonBorder(enabled = enabled), - colors: ButtonColors = NiaButtonDefaults.outlinedButtonColors(), text: @Composable () -> Unit, - leadingIcon: @Composable (() -> Unit)? = null, - trailingIcon: @Composable (() -> Unit)? = null + leadingIcon: @Composable (() -> Unit)? = null ) { NiaOutlinedButton( onClick = onClick, modifier = modifier, enabled = enabled, - small = small, - border = border, - colors = colors, - contentPadding = NiaButtonDefaults.buttonContentPadding( - small = small, - leadingIcon = leadingIcon != null, - trailingIcon = trailingIcon != null - ) + contentPadding = if (leadingIcon != null) { + ButtonDefaults.ButtonWithIconContentPadding + } else { + ButtonDefaults.ContentPadding + } ) { NiaButtonContent( text = text, - leadingIcon = leadingIcon, - trailingIcon = trailingIcon + leadingIcon = leadingIcon ) } } @@ -223,11 +180,6 @@ fun NiaOutlinedButton( * @param modifier Modifier to be applied to the button. * @param enabled Controls the enabled state of the button. When `false`, this button will not be * clickable and will appear disabled to accessibility services. - * @param small Whether or not the size of the button should be small or regular. - * @param colors [ButtonColors] that will be used to resolve the container and content color for - * this button in different states. See [NiaButtonDefaults.textButtonColors]. - * @param contentPadding The spacing values to apply internally between the container and the - * content. See [NiaButtonDefaults.buttonContentPadding]. * @param content The button content. */ @Composable @@ -235,26 +187,16 @@ fun NiaTextButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - small: Boolean = false, - colors: ButtonColors = NiaButtonDefaults.textButtonColors(), - contentPadding: PaddingValues = NiaButtonDefaults.buttonContentPadding(small = small), content: @Composable RowScope.() -> Unit ) { TextButton( onClick = onClick, - modifier = if (small) { - modifier.heightIn(min = NiaButtonDefaults.SmallButtonHeight) - } else { - modifier - }, + modifier = modifier, enabled = enabled, - colors = colors, - contentPadding = contentPadding, - content = { - ProvideTextStyle(value = MaterialTheme.typography.labelSmall) { - content() - } - } + colors = ButtonDefaults.textButtonColors( + contentColor = MaterialTheme.colorScheme.onBackground + ), + content = content ) } @@ -265,60 +207,42 @@ fun NiaTextButton( * @param modifier Modifier to be applied to the button. * @param enabled Controls the enabled state of the button. When `false`, this button will not be * clickable and will appear disabled to accessibility services. - * @param small Whether or not the size of the button should be small or regular. - * @param colors [ButtonColors] that will be used to resolve the container and content color for - * this button in different states. See [NiaButtonDefaults.textButtonColors]. * @param text The button text label content. * @param leadingIcon The button leading icon content. Pass `null` here for no leading icon. - * @param trailingIcon The button trailing icon content. Pass `null` here for no trailing icon. */ @Composable fun NiaTextButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - small: Boolean = false, - colors: ButtonColors = NiaButtonDefaults.textButtonColors(), text: @Composable () -> Unit, - leadingIcon: @Composable (() -> Unit)? = null, - trailingIcon: @Composable (() -> Unit)? = null + leadingIcon: @Composable (() -> Unit)? = null ) { NiaTextButton( onClick = onClick, modifier = modifier, - enabled = enabled, - small = small, - colors = colors, - contentPadding = NiaButtonDefaults.buttonContentPadding( - small = small, - leadingIcon = leadingIcon != null, - trailingIcon = trailingIcon != null - ) + enabled = enabled ) { NiaButtonContent( text = text, - leadingIcon = leadingIcon, - trailingIcon = trailingIcon + leadingIcon = leadingIcon ) } } /** - * Internal Now in Android button content layout for arranging the text label, leading icon and - * trailing icon. + * Internal Now in Android button content layout for arranging the text label and leading icon. * * @param text The button text label content. - * @param leadingIcon The button leading icon content. Pass `null` here for no leading icon. - * @param trailingIcon The button trailing icon content. Pass `null` here for no trailing icon. + * @param leadingIcon The button leading icon content. Default is `null` for no leading icon.Ï */ @Composable -private fun RowScope.NiaButtonContent( +private fun NiaButtonContent( text: @Composable () -> Unit, - leadingIcon: @Composable (() -> Unit)?, - trailingIcon: @Composable (() -> Unit)? + leadingIcon: @Composable (() -> Unit)? = null ) { if (leadingIcon != null) { - Box(Modifier.sizeIn(maxHeight = NiaButtonDefaults.ButtonIconSize)) { + Box(Modifier.sizeIn(maxHeight = ButtonDefaults.IconSize)) { leadingIcon() } } @@ -326,12 +250,7 @@ private fun RowScope.NiaButtonContent( Modifier .padding( start = if (leadingIcon != null) { - NiaButtonDefaults.ButtonContentSpacing - } else { - 0.dp - }, - end = if (trailingIcon != null) { - NiaButtonDefaults.ButtonContentSpacing + ButtonDefaults.IconSpacing } else { 0.dp } @@ -339,104 +258,16 @@ private fun RowScope.NiaButtonContent( ) { text() } - if (trailingIcon != null) { - Box(Modifier.sizeIn(maxHeight = NiaButtonDefaults.ButtonIconSize)) { - trailingIcon() - } - } } /** * Now in Android button default values. */ object NiaButtonDefaults { - val SmallButtonHeight = 32.dp - const val DisabledButtonContainerAlpha = 0.12f - const val DisabledButtonContentAlpha = 0.38f - val ButtonHorizontalPadding = 24.dp - val ButtonHorizontalIconPadding = 16.dp - val ButtonVerticalPadding = 8.dp - val SmallButtonHorizontalPadding = 16.dp - val SmallButtonHorizontalIconPadding = 12.dp - val SmallButtonVerticalPadding = 7.dp - val ButtonContentSpacing = 8.dp - val ButtonIconSize = 18.dp - fun buttonContentPadding( - small: Boolean, - leadingIcon: Boolean = false, - trailingIcon: Boolean = false - ): PaddingValues { - return PaddingValues( - start = when { - small && leadingIcon -> SmallButtonHorizontalIconPadding - small -> SmallButtonHorizontalPadding - leadingIcon -> ButtonHorizontalIconPadding - else -> ButtonHorizontalPadding - }, - top = if (small) SmallButtonVerticalPadding else ButtonVerticalPadding, - end = when { - small && trailingIcon -> SmallButtonHorizontalIconPadding - small -> SmallButtonHorizontalPadding - trailingIcon -> ButtonHorizontalIconPadding - else -> ButtonHorizontalPadding - }, - bottom = if (small) SmallButtonVerticalPadding else ButtonVerticalPadding - ) - } - @Composable - fun filledButtonColors( - containerColor: Color = MaterialTheme.colorScheme.onBackground, - contentColor: Color = MaterialTheme.colorScheme.onPrimary, - disabledContainerColor: Color = MaterialTheme.colorScheme.onBackground.copy( - alpha = DisabledButtonContainerAlpha - ), - disabledContentColor: Color = MaterialTheme.colorScheme.onBackground.copy( - alpha = DisabledButtonContentAlpha - ) - ) = ButtonDefaults.buttonColors( - containerColor = containerColor, - contentColor = contentColor, - disabledContainerColor = disabledContainerColor, - disabledContentColor = disabledContentColor - ) - @Composable - fun outlinedButtonBorder( - enabled: Boolean, - width: Dp = 1.dp, - color: Color = MaterialTheme.colorScheme.onBackground, - disabledColor: Color = MaterialTheme.colorScheme.onBackground.copy( - alpha = DisabledButtonContainerAlpha - ) - ): BorderStroke = BorderStroke( - width = width, - color = if (enabled) color else disabledColor - ) - @Composable - fun outlinedButtonColors( - containerColor: Color = Color.Transparent, - contentColor: Color = MaterialTheme.colorScheme.onBackground, - disabledContainerColor: Color = Color.Transparent, - disabledContentColor: Color = MaterialTheme.colorScheme.onBackground.copy( - alpha = DisabledButtonContentAlpha - ) - ) = ButtonDefaults.outlinedButtonColors( - containerColor = containerColor, - contentColor = contentColor, - disabledContainerColor = disabledContainerColor, - disabledContentColor = disabledContentColor - ) - @Composable - fun textButtonColors( - containerColor: Color = Color.Transparent, - contentColor: Color = MaterialTheme.colorScheme.onBackground, - disabledContainerColor: Color = Color.Transparent, - disabledContentColor: Color = MaterialTheme.colorScheme.onBackground.copy( - alpha = DisabledButtonContentAlpha - ) - ) = ButtonDefaults.textButtonColors( - containerColor = containerColor, - contentColor = contentColor, - disabledContainerColor = disabledContainerColor, - disabledContentColor = disabledContentColor - ) + // TODO: File bug + // OutlinedButton border color doesn't respect disabled state by default + const val DisabledOutlinedButtonBorderAlpha = 0.12f + // TODO: File bug + // OutlinedButton default border width isn't exposed via ButtonDefaults + val OutlinedButtonBorderWidth = 1.dp } diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Chip.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Chip.kt index 017238e07..663667861 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Chip.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Chip.kt @@ -58,11 +58,15 @@ fun NiaFilterChip( }, modifier = modifier, enabled = enabled, - trailingIcon = { - Icon( - imageVector = NiaIcons.Check, - contentDescription = null - ) + leadingIcon = if (selected) { + { + Icon( + imageVector = NiaIcons.Check, + contentDescription = null + ) + } + } else { + null }, shape = CircleShape, border = FilterChipDefaults.filterChipBorder( @@ -74,11 +78,9 @@ fun NiaFilterChip( disabledSelectedBorderColor = MaterialTheme.colorScheme.onBackground.copy( alpha = NiaChipDefaults.DisabledChipContentAlpha ), - borderWidth = NiaChipDefaults.ChipBorderWidth, selectedBorderWidth = NiaChipDefaults.ChipBorderWidth ), colors = FilterChipDefaults.filterChipColors( - containerColor = Color.Transparent, labelColor = MaterialTheme.colorScheme.onBackground, iconColor = MaterialTheme.colorScheme.onBackground, disabledContainerColor = if (selected) { @@ -105,6 +107,8 @@ fun NiaFilterChip( * Now in Android chip default values. */ object NiaChipDefaults { + // TODO: File bug + // FilterChip default values aren't exposed via FilterChipDefaults const val DisabledChipContainerAlpha = 0.12f const val DisabledChipContentAlpha = 0.38f val ChipBorderWidth = 1.dp diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DropdownMenu.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DropdownMenu.kt index 270fd07a6..b8d3fa837 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DropdownMenu.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/DropdownMenu.kt @@ -16,16 +16,25 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.ProvideTextStyle 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.unit.dp import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons /** @@ -56,17 +65,38 @@ fun NiaDropdownMenuButton( ) { var expanded by remember { mutableStateOf(false) } Box(modifier = modifier) { - NiaOutlinedButton( + OutlinedButton( onClick = { expanded = true }, enabled = enabled, - text = text, - trailingIcon = { - Icon( - imageVector = if (expanded) NiaIcons.ArrowDropUp else NiaIcons.ArrowDropDown, - contentDescription = null - ) - } - ) + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.onBackground + ), + border = BorderStroke( + width = NiaDropdownMenuDefaults.DropdownMenuButtonBorderWidth, + color = if (enabled) { + MaterialTheme.colorScheme.outline + } else { + MaterialTheme.colorScheme.onSurface.copy( + alpha = NiaDropdownMenuDefaults.DisabledDropdownMenuButtonBorderAlpha + ) + } + ), + contentPadding = NiaDropdownMenuDefaults.DropdownMenuButtonContentPadding + ) { + NiaDropdownMenuButtonContent( + text = text, + trailingIcon = { + Icon( + imageVector = if (expanded) { + NiaIcons.ArrowDropUp + } else { + NiaIcons.ArrowDropDown + }, + contentDescription = null + ) + } + ) + } NiaDropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, @@ -80,6 +110,39 @@ fun NiaDropdownMenuButton( } } +/** + * Internal Now in Android dropdown menu button content layout for arranging the text label and + * trailing icon. + * + * @param text The button text label content. + * @param trailingIcon The button trailing icon content. Default is `null` for no trailing icon. + */ +@Composable +private fun NiaDropdownMenuButtonContent( + text: @Composable () -> Unit, + trailingIcon: @Composable (() -> Unit)? = null, +) { + Box( + Modifier + .padding( + end = if (trailingIcon != null) { + ButtonDefaults.IconSpacing + } else { + 0.dp + } + ) + ) { + ProvideTextStyle(value = MaterialTheme.typography.labelSmall) { + text() + } + } + if (trailingIcon != null) { + Box(Modifier.sizeIn(maxHeight = ButtonDefaults.IconSize)) { + trailingIcon() + } + } +} + /** * Now in Android dropdown menu with item content slots. Wraps Material 3 [DropdownMenu] and * [DropdownMenuItem]. @@ -130,3 +193,24 @@ fun NiaDropdownMenu( } } } + +/** + * Now in Android dropdown menu default values. + */ +object NiaDropdownMenuDefaults { + // TODO: File bug + // OutlinedButton border color doesn't respect disabled state by default + const val DisabledDropdownMenuButtonBorderAlpha = 0.12f + // TODO: File bug + // OutlinedButton default border width isn't exposed via ButtonDefaults + val DropdownMenuButtonBorderWidth = 1.dp + // TODO: File bug + // Various default button padding values aren't exposed via ButtonDefaults + val DropdownMenuButtonContentPadding = + PaddingValues( + start = 24.dp, + top = 8.dp, + end = 16.dp, + bottom = 8.dp + ) +} diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/IconButton.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/IconButton.kt new file mode 100644 index 000000000..0eedf23f7 --- /dev/null +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/IconButton.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.samples.apps.nowinandroid.core.designsystem.component + +import androidx.compose.material3.FilledIconToggleButton +import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color + +/** + * Now in Android toggle button with icon and checked icon content slots. Wraps Material 3 + * [IconButton]. + * + * @param checked Whether the toggle button is currently checked. + * @param onCheckedChange Called when the user clicks the toggle button and toggles checked. + * @param modifier Modifier to be applied to the toggle button. + * @param enabled Controls the enabled state of the toggle button. When `false`, this toggle button + * will not be clickable and will appear disabled to accessibility services. + * @param icon The icon content to show when unchecked. + * @param checkedIcon The icon content to show when checked. + */ +@Composable +fun NiaIconToggleButton( + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + icon: @Composable () -> Unit, + checkedIcon: @Composable () -> Unit = icon +) { + // TODO: File bug + // Can't use regular IconToggleButton as it doesn't include a shape (appears square) + FilledIconToggleButton( + checked = checked, + onCheckedChange = onCheckedChange, + modifier = modifier, + enabled = enabled, + colors = IconButtonDefaults.iconToggleButtonColors( + checkedContainerColor = MaterialTheme.colorScheme.primaryContainer, + checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer, + disabledContainerColor = if (checked) { + MaterialTheme.colorScheme.onBackground.copy( + alpha = NiaIconButtonDefaults.DisabledIconButtonContainerAlpha + ) + } else { + Color.Transparent + } + ) + ) { + if (checked) checkedIcon() else icon() + } +} + +/** + * Now in Android icon button default values. + */ +object NiaIconButtonDefaults { + // TODO: File bug + // IconToggleButton disabled container alpha not exposed by IconButtonDefaults + const val DisabledIconButtonContainerAlpha = 0.12f +} diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Tag.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Tag.kt index 6a2475931..dae42421c 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Tag.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/Tag.kt @@ -17,24 +17,26 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component import androidx.compose.foundation.layout.Box +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import com.google.samples.apps.nowinandroid.core.designsystem.R @Composable fun NiaTopicTag( + modifier: Modifier = Modifier, expanded: Boolean = false, followed: Boolean, - onDropMenuToggle: (show: Boolean) -> Unit = {}, + onDropdownMenuToggle: (show: Boolean) -> Unit = {}, onFollowClick: () -> Unit, onUnfollowClick: () -> Unit, onBrowseClick: () -> Unit, - modifier: Modifier = Modifier, enabled: Boolean = true, text: @Composable () -> Unit, followText: @Composable () -> Unit = { Text(stringResource(R.string.follow)) }, @@ -46,28 +48,28 @@ fun NiaTopicTag( val containerColor = if (followed) { MaterialTheme.colorScheme.primaryContainer } else { - MaterialTheme.colorScheme.surfaceVariant + MaterialTheme.colorScheme.surfaceVariant.copy( + alpha = NiaTagDefaults.UnfollowedTopicTagContainerAlpha + ) } - NiaTextButton( - onClick = { onDropMenuToggle(true) }, + TextButton( + onClick = { onDropdownMenuToggle(true) }, enabled = enabled, - small = true, - colors = NiaButtonDefaults.textButtonColors( + colors = ButtonDefaults.textButtonColors( containerColor = containerColor, contentColor = contentColorFor(backgroundColor = containerColor), - disabledContainerColor = if (followed) { - MaterialTheme.colorScheme.onBackground.copy( - alpha = NiaButtonDefaults.DisabledButtonContentAlpha - ) - } else { - Color.Transparent - } - ), - text = text - ) + disabledContainerColor = MaterialTheme.colorScheme.onSurface.copy( + alpha = NiaTagDefaults.DisabledTopicTagContainerAlpha + ) + ) + ) { + ProvideTextStyle(value = MaterialTheme.typography.labelSmall) { + text() + } + } NiaDropdownMenu( expanded = expanded, - onDismissRequest = { onDropMenuToggle(false) }, + onDismissRequest = { onDropdownMenuToggle(false) }, items = if (followed) listOf(UNFOLLOW, BROWSE) else listOf(FOLLOW, BROWSE), onItemClick = { item -> when (item) { @@ -87,6 +89,16 @@ fun NiaTopicTag( } } +/** + * Now in Android tag default values. + */ +object NiaTagDefaults { + const val UnfollowedTopicTagContainerAlpha = 0.5f + // TODO: File bug + // Button disabled container alpha value not exposed by ButtonDefaults + const val DisabledTopicTagContainerAlpha = 0.12f +} + private const val FOLLOW = 1 private const val UNFOLLOW = 2 private const val BROWSE = 3 diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ToggleButton.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ToggleButton.kt deleted file mode 100644 index 955aed9a7..000000000 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ToggleButton.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.samples.apps.nowinandroid.core.designsystem.component - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.sizeIn -import androidx.compose.foundation.selection.toggleable -import androidx.compose.material3.IconButton -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.contentColorFor -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawBehind -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp - -/** - * Now in Android toggle button with icon and checked icon content slots. Wraps Material 3 - * [IconButton]. - * - * @param checked Whether the toggle button is currently checked. - * @param onCheckedChange Called when the user clicks the toggle button and toggles checked. - * @param modifier Modifier to be applied to the toggle button. - * @param enabled Controls the enabled state of the toggle button. When `false`, this toggle button - * will not be clickable and will appear disabled to accessibility services. - * @param icon The icon content to show when unchecked. - * @param checkedIcon The icon content to show when checked. - * @param size The size of the toggle button. - * @param iconSize The size of the icon. - * @param backgroundColor The background color when unchecked. - * @param checkedBackgroundColor The background color when checked. - * @param iconColor The icon color when unchecked. - * @param iconColor The icon color when checked. - */ -@Composable -fun NiaToggleButton( - checked: Boolean, - onCheckedChange: (Boolean) -> Unit, - modifier: Modifier = Modifier, - enabled: Boolean = true, - icon: @Composable () -> Unit, - checkedIcon: @Composable () -> Unit = icon, - size: Dp = NiaToggleButtonDefaults.ToggleButtonSize, - iconSize: Dp = NiaToggleButtonDefaults.ToggleButtonIconSize, - backgroundColor: Color = Color.Transparent, - checkedBackgroundColor: Color = MaterialTheme.colorScheme.primaryContainer, - iconColor: Color = contentColorFor(backgroundColor), - checkedIconColor: Color = contentColorFor(checkedBackgroundColor) -) { - val radius = with(LocalDensity.current) { (size / 2).toPx() } - IconButton( - onClick = { onCheckedChange(!checked) }, - modifier = modifier - .size(size) - .toggleable(value = checked, enabled = enabled, role = Role.Button, onValueChange = { - onCheckedChange(!checked) - }) - .drawBehind { - drawCircle( - color = if (checked) checkedBackgroundColor else backgroundColor, - radius = radius - ) - }, - enabled = enabled, - content = { - Box( - modifier = Modifier.sizeIn( - maxWidth = iconSize, - maxHeight = iconSize - ) - ) { - val contentColor = if (checked) checkedIconColor else iconColor - CompositionLocalProvider(LocalContentColor provides contentColor) { - if (checked) checkedIcon() else icon() - } - } - } - ) -} - -/** - * Now in Android toggle button default values. - */ -object NiaToggleButtonDefaults { - val ToggleButtonSize = 40.dp - val ToggleButtonIconSize = 18.dp -} diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt index 2175a1684..4fa9e297f 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/TopAppBar.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalMaterial3Api::class) + package com.google.samples.apps.nowinandroid.core.designsystem.component import androidx.annotation.StringRes diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ViewToggle.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ViewToggle.kt index a8267040a..a6721c78c 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ViewToggle.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/component/ViewToggle.kt @@ -16,9 +16,18 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ProvideTextStyle +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons /** @@ -42,16 +51,71 @@ fun NiaViewToggleButton( compactText: @Composable () -> Unit, expandedText: @Composable () -> Unit ) { - NiaTextButton( + TextButton( onClick = { onExpandedChange(!expanded) }, modifier = modifier, enabled = enabled, - text = if (expanded) expandedText else compactText, - trailingIcon = { - Icon( - imageVector = if (expanded) NiaIcons.ViewDay else NiaIcons.ShortText, - contentDescription = null + colors = ButtonDefaults.textButtonColors( + contentColor = MaterialTheme.colorScheme.onBackground + ), + contentPadding = NiaViewToggleDefaults.ViewToggleButtonContentPadding + ) { + NiaViewToggleButtonContent( + text = if (expanded) expandedText else compactText, + trailingIcon = { + Icon( + imageVector = if (expanded) NiaIcons.ViewDay else NiaIcons.ShortText, + contentDescription = null + ) + } + ) + } +} + +/** + * Internal Now in Android view toggle button content layout for arranging the text label and + * trailing icon. + * + * @param text The button text label content. + * @param trailingIcon The button trailing icon content. Default is `null` for no trailing icon. + */ +@Composable +private fun NiaViewToggleButtonContent( + text: @Composable () -> Unit, + trailingIcon: @Composable (() -> Unit)? = null, +) { + Box( + Modifier + .padding( + end = if (trailingIcon != null) { + ButtonDefaults.IconSpacing + } else { + 0.dp + } ) + ) { + ProvideTextStyle(value = MaterialTheme.typography.labelSmall) { + text() + } + } + if (trailingIcon != null) { + Box(Modifier.sizeIn(maxHeight = ButtonDefaults.IconSize)) { + trailingIcon() } - ) + } +} + +/** + * Now in Android view toggle default values. + */ +object NiaViewToggleDefaults { + // TODO: File bug + // Various default button padding values aren't exposed via ButtonDefaults + val ViewToggleButtonContentPadding = + PaddingValues( + start = 16.dp, + top = 8.dp, + end = 12.dp, + bottom = 8.dp + ) } diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/icon/NiaIcons.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/icon/NiaIcons.kt index c5367425d..5646f088a 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/icon/NiaIcons.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/icon/NiaIcons.kt @@ -18,12 +18,12 @@ package com.google.samples.apps.nowinandroid.core.designsystem.icon import androidx.annotation.DrawableRes import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material.icons.filled.ArrowDropUp import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.outlined.AccountCircle import androidx.compose.material.icons.rounded.Add import androidx.compose.material.icons.rounded.ArrowBack -import androidx.compose.material.icons.rounded.ArrowDropDown -import androidx.compose.material.icons.rounded.ArrowDropUp import androidx.compose.material.icons.rounded.Check import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.ExpandLess @@ -48,8 +48,8 @@ object NiaIcons { val AccountCircle = Icons.Outlined.AccountCircle val Add = Icons.Rounded.Add val ArrowBack = Icons.Rounded.ArrowBack - val ArrowDropDown = Icons.Rounded.ArrowDropDown - val ArrowDropUp = Icons.Rounded.ArrowDropUp + val ArrowDropDown = Icons.Default.ArrowDropDown + val ArrowDropUp = Icons.Default.ArrowDropUp val Bookmark = R.drawable.ic_bookmark val BookmarkBorder = R.drawable.ic_bookmark_border val Bookmarks = R.drawable.ic_bookmarks diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Color.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Color.kt index 50c6f972f..ec4fa76b7 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Color.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Color.kt @@ -21,13 +21,13 @@ import androidx.compose.ui.graphics.Color /** * Now in Android colors. */ -internal val Blue10 = Color(0xFF001F29) +internal val Blue10 = Color(0xFF001F28) internal val Blue20 = Color(0xFF003544) internal val Blue30 = Color(0xFF004D61) -internal val Blue40 = Color(0xFF006781) -internal val Blue80 = Color(0xFF5DD4FB) -internal val Blue90 = Color(0xFFB5EAFF) -internal val Blue95 = Color(0xFFDCF5FF) +internal val Blue40 = Color(0xFF006780) +internal val Blue80 = Color(0xFF5DD5FC) +internal val Blue90 = Color(0xFFB8EAFF) +internal val Blue95 = Color(0xFFDDF4FF) internal val DarkGreen10 = Color(0xFF0D1F12) internal val DarkGreen20 = Color(0xFF223526) internal val DarkGreen30 = Color(0xFF394B3C) @@ -35,10 +35,12 @@ internal val DarkGreen40 = Color(0xFF4F6352) internal val DarkGreen80 = Color(0xFFB7CCB8) internal val DarkGreen90 = Color(0xFFD3E8D3) internal val DarkGreenGray10 = Color(0xFF1A1C1A) +internal val DarkGreenGray20 = Color(0xFF2F312E) internal val DarkGreenGray90 = Color(0xFFE2E3DE) internal val DarkGreenGray95 = Color(0xFFF0F1EC) internal val DarkGreenGray99 = Color(0xFFFBFDF7) internal val DarkPurpleGray10 = Color(0xFF201A1B) +internal val DarkPurpleGray20 = Color(0xFF362F30) internal val DarkPurpleGray90 = Color(0xFFECDFE0) internal val DarkPurpleGray95 = Color(0xFFFAEEEF) internal val DarkPurpleGray99 = Color(0xFFFCFCFC) @@ -53,31 +55,31 @@ internal val GreenGray50 = Color(0xFF727971) internal val GreenGray60 = Color(0xFF8B938A) internal val GreenGray80 = Color(0xFFC1C9BF) internal val GreenGray90 = Color(0xFFDDE5DB) -internal val Orange10 = Color(0xFF390C00) -internal val Orange20 = Color(0xFF5D1900) +internal val Orange10 = Color(0xFF380D00) +internal val Orange20 = Color(0xFF5B1A00) internal val Orange30 = Color(0xFF812800) internal val Orange40 = Color(0xFFA23F16) -internal val Orange80 = Color(0xFFFFB599) -internal val Orange90 = Color(0xFFFFDBCE) -internal val Orange95 = Color(0xFFFFEDE6) -internal val Purple10 = Color(0xFF36003D) -internal val Purple20 = Color(0xFF560A5E) +internal val Orange80 = Color(0xFFFFB59B) +internal val Orange90 = Color(0xFFFFDBCF) +internal val Orange95 = Color(0xFFFFEDE8) +internal val Purple10 = Color(0xFF36003C) +internal val Purple20 = Color(0xFF560A5D) internal val Purple30 = Color(0xFF702776) -internal val Purple40 = Color(0xFF8C4190) -internal val Purple80 = Color(0xFFFFA8FF) -internal val Purple90 = Color(0xFFFFD5FC) -internal val Purple95 = Color(0xFFFFEBFB) -internal val PurpleGray30 = Color(0xFF4E444C) +internal val Purple40 = Color(0xFF8B418F) +internal val Purple80 = Color(0xFFFFA9FE) +internal val Purple90 = Color(0xFFFFD6FA) +internal val Purple95 = Color(0xFFFFEBFA) +internal val PurpleGray30 = Color(0xFF4D444C) internal val PurpleGray50 = Color(0xFF7F747C) internal val PurpleGray60 = Color(0xFF998D96) -internal val PurpleGray80 = Color(0xFFD0C2CC) +internal val PurpleGray80 = Color(0xFFD0C3CC) internal val PurpleGray90 = Color(0xFFEDDEE8) -internal val Red10 = Color(0xFF410001) -internal val Red20 = Color(0xFF680003) -internal val Red30 = Color(0xFF930006) -internal val Red40 = Color(0xFFBA1B1B) -internal val Red80 = Color(0xFFFFB4A9) -internal val Red90 = Color(0xFFFFDAD4) +internal val Red10 = Color(0xFF410002) +internal val Red20 = Color(0xFF690005) +internal val Red30 = Color(0xFF93000A) +internal val Red40 = Color(0xFFBA1A1A) +internal val Red80 = Color(0xFFFFB4AB) +internal val Red90 = Color(0xFFFFDAD6) internal val Teal10 = Color(0xFF001F26) internal val Teal20 = Color(0xFF02363F) internal val Teal30 = Color(0xFF214D56) diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Gradient.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Gradient.kt index 7ecaa94b8..c77041e21 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Gradient.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Gradient.kt @@ -25,10 +25,9 @@ import androidx.compose.ui.graphics.Color */ @Immutable data class GradientColors( - val primary: Color = Color.Unspecified, - val secondary: Color = Color.Unspecified, - val tertiary: Color = Color.Unspecified, - val neutral: Color = Color.Unspecified + val top: Color = Color.Unspecified, + val bottom: Color = Color.Unspecified, + val container: Color = Color.Unspecified ) /** diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Theme.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Theme.kt index 10f0c3898..80b635be0 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Theme.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Theme.kt @@ -58,6 +58,8 @@ val LightDefaultColorScheme = lightColorScheme( onSurface = DarkPurpleGray10, surfaceVariant = PurpleGray90, onSurfaceVariant = PurpleGray30, + inverseSurface = DarkPurpleGray20, + inverseOnSurface = DarkPurpleGray95, outline = PurpleGray50 ) @@ -88,6 +90,8 @@ val DarkDefaultColorScheme = darkColorScheme( onSurface = DarkPurpleGray90, surfaceVariant = PurpleGray30, onSurfaceVariant = PurpleGray80, + inverseSurface = DarkPurpleGray90, + inverseOnSurface = DarkPurpleGray10, outline = PurpleGray60 ) @@ -118,6 +122,8 @@ val LightAndroidColorScheme = lightColorScheme( onSurface = DarkGreenGray10, surfaceVariant = GreenGray90, onSurfaceVariant = GreenGray30, + inverseSurface = DarkGreenGray20, + inverseOnSurface = DarkGreenGray95, outline = GreenGray50 ) @@ -148,19 +154,11 @@ val DarkAndroidColorScheme = darkColorScheme( onSurface = DarkGreenGray90, surfaceVariant = GreenGray30, onSurfaceVariant = GreenGray80, + inverseSurface = DarkGreenGray90, + inverseOnSurface = DarkGreenGray10, outline = GreenGray60 ) -/** - * Light default gradient colors - */ -val LightDefaultGradientColors = GradientColors( - primary = Purple95, - secondary = Orange95, - tertiary = Blue95, - neutral = DarkPurpleGray95 -) - /** * Light Android background theme */ @@ -207,32 +205,48 @@ internal fun NiaTheme( disableDynamicTheming: Boolean, content: @Composable () -> Unit ) { - val colorScheme = if (androidTheme) { - if (darkTheme) DarkAndroidColorScheme else LightAndroidColorScheme - } else if (!disableDynamicTheming && supportsDynamicTheming()) { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } else { - if (darkTheme) DarkDefaultColorScheme else LightDefaultColorScheme + // Color scheme + val colorScheme = when { + !disableDynamicTheming -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } else { + if (darkTheme) DarkDefaultColorScheme else LightDefaultColorScheme + } + } + androidTheme -> if (darkTheme) DarkAndroidColorScheme else LightAndroidColorScheme + else -> if (darkTheme) DarkDefaultColorScheme else LightDefaultColorScheme } - - val defaultGradientColors = GradientColors() - val gradientColors = if (androidTheme || (!disableDynamicTheming && supportsDynamicTheming())) { - defaultGradientColors - } else { - if (darkTheme) defaultGradientColors else LightDefaultGradientColors + // Gradient colors + val emptyGradientColors = GradientColors() + val defaultGradientColors = GradientColors( + top = colorScheme.inverseOnSurface, + bottom = colorScheme.primaryContainer, + container = colorScheme.surface + ) + val gradientColors = when { + !disableDynamicTheming -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + emptyGradientColors + } else { + defaultGradientColors + } + } + androidTheme -> emptyGradientColors + else -> defaultGradientColors } - + // Background theme val defaultBackgroundTheme = BackgroundTheme( color = colorScheme.surface, tonalElevation = 2.dp ) - val backgroundTheme = if (androidTheme) { - if (darkTheme) DarkAndroidBackgroundTheme else LightAndroidBackgroundTheme - } else { - defaultBackgroundTheme + val backgroundTheme = when { + !disableDynamicTheming -> defaultBackgroundTheme + androidTheme -> if (darkTheme) DarkAndroidBackgroundTheme else LightAndroidBackgroundTheme + else -> defaultBackgroundTheme } - + // Composition locals CompositionLocalProvider( LocalGradientColors provides gradientColors, LocalBackgroundTheme provides backgroundTheme diff --git a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt index 9d8fb8df8..7c9621caf 100644 --- a/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt +++ b/core/designsystem/src/main/java/com/google/samples/apps/nowinandroid/core/designsystem/theme/Type.kt @@ -18,98 +18,101 @@ package com.google.samples.apps.nowinandroid.core.designsystem.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp /** * Now in Android typography. - * - * TODO: Add custom font */ internal val NiaTypography = Typography( displayLarge = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 57.sp, lineHeight = 64.sp, letterSpacing = (-0.25).sp ), displayMedium = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 45.sp, - lineHeight = 52.sp + lineHeight = 52.sp, + letterSpacing = 0.sp ), displaySmall = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 36.sp, - lineHeight = 44.sp + lineHeight = 44.sp, + letterSpacing = 0.sp ), headlineLarge = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 32.sp, - lineHeight = 40.sp + lineHeight = 40.sp, + letterSpacing = 0.sp ), headlineMedium = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 28.sp, - lineHeight = 36.sp + lineHeight = 36.sp, + letterSpacing = 0.sp ), headlineSmall = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 24.sp, - lineHeight = 32.sp + lineHeight = 32.sp, + letterSpacing = 0.sp ), titleLarge = TextStyle( - fontWeight = FontWeight.W700, + fontWeight = FontWeight.Bold, fontSize = 22.sp, - lineHeight = 28.sp + lineHeight = 28.sp, + letterSpacing = 0.sp ), titleMedium = TextStyle( - fontWeight = FontWeight.W700, - fontSize = 16.sp, + fontWeight = FontWeight.Bold, + fontSize = 18.sp, lineHeight = 24.sp, letterSpacing = 0.1.sp ), titleSmall = TextStyle( - fontWeight = FontWeight.W500, + fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp ), bodyLarge = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.5.sp ), bodyMedium = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.25.sp ), bodySmall = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.4.sp ), labelLarge = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp ), labelMedium = TextStyle( - fontWeight = FontWeight.W400, + fontWeight = FontWeight.Medium, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.5.sp ), labelSmall = TextStyle( - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.W500, + fontWeight = FontWeight.Medium, fontSize = 10.sp, - lineHeight = 16.sp + lineHeight = 16.sp, + letterSpacing = 0.sp ) ) diff --git a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index c7d04680c..21ee1a7a8 100644 --- a/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core/ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -52,7 +52,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.designsystem.R as DesignsystemR -import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaToggleButton +import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme @@ -156,7 +156,7 @@ fun BookmarkButton( onClick: () -> Unit, modifier: Modifier = Modifier ) { - NiaToggleButton( + NiaIconToggleButton( checked = isBookmarked, onCheckedChange = { onClick() }, modifier = modifier, @@ -242,7 +242,7 @@ fun NewsResourceTopics( NiaTopicTag( expanded = expandedTopicId == topic.id, followed = true, // ToDo: Check if topic is followed - onDropMenuToggle = { show -> + onDropdownMenuToggle = { show -> expandedTopicId = if (show) topic.id else null }, onFollowClick = { }, // ToDo diff --git a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 1420a7e47..1427aecff 100644 --- a/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature/foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -77,9 +77,9 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage -import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilledButton +import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaButton +import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaOverlayLoadingWheel -import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.domain.model.FollowableTopic @@ -257,7 +257,7 @@ private fun LazyGridScope.onboarding( horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth() ) { - NiaFilledButton( + NiaButton( onClick = saveFollowedTopics, enabled = onboardingUiState.isDismissable, modifier = Modifier @@ -350,7 +350,7 @@ private fun SingleTopicButton( .weight(1f), color = MaterialTheme.colorScheme.onSurface ) - NiaToggleButton( + NiaIconToggleButton( checked = isSelected, onCheckedChange = { checked -> onClick(topicId, checked) }, icon = { diff --git a/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsItem.kt b/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsItem.kt index 3cfbea53e..32e645094 100644 --- a/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsItem.kt +++ b/feature/interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsItem.kt @@ -37,7 +37,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import coil.compose.AsyncImage -import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaToggleButton +import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme import com.google.samples.apps.nowinandroid.feature.interests.R.string @@ -69,7 +69,7 @@ fun InterestsItem( Spacer(modifier = Modifier.width(16.dp)) InterestContent(name, description) } - NiaToggleButton( + NiaIconToggleButton( checked = following, onCheckedChange = onFollowButtonClick, icon = { diff --git a/lint/src/main/java/com/google/samples/apps/nowinandroid/lint/designsystem/DesignSystemDetector.kt b/lint/src/main/java/com/google/samples/apps/nowinandroid/lint/designsystem/DesignSystemDetector.kt index 392d03607..047b5d7ab 100644 --- a/lint/src/main/java/com/google/samples/apps/nowinandroid/lint/designsystem/DesignSystemDetector.kt +++ b/lint/src/main/java/com/google/samples/apps/nowinandroid/lint/designsystem/DesignSystemDetector.kt @@ -80,7 +80,7 @@ class DesignSystemDetector : Detector(), Detector.UastScanner { // instead of hardcoded names. val METHOD_NAMES = mapOf( "MaterialTheme" to "NiaTheme", - "Button" to "NiaFilledButton", + "Button" to "NiaButton", "OutlinedButton" to "NiaOutlinedButton", "TextButton" to "NiaTextButton", "FilterChip" to "NiaFilterChip", @@ -92,10 +92,10 @@ class DesignSystemDetector : Detector(), Detector.UastScanner { "NavigationRailItem" to "NiaNavigationRailItem", "TabRow" to "NiaTabRow", "Tab" to "NiaTab", - "IconToggleButton" to "NiaToggleButton", - "FilledIconToggleButton" to "NiaToggleButton", - "FilledTonalIconToggleButton" to "NiaToggleButton", - "OutlinedIconToggleButton" to "NiaToggleButton", + "IconToggleButton" to "NiaIconToggleButton", + "FilledIconToggleButton" to "NiaIconToggleButton", + "FilledTonalIconToggleButton" to "NiaIconToggleButton", + "OutlinedIconToggleButton" to "NiaIconToggleButton", "CenterAlignedTopAppBar" to "NiaTopAppBar", "SmallTopAppBar" to "NiaTopAppBar", "MediumTopAppBar" to "NiaTopAppBar",