diff options
4 files changed, 457 insertions, 3 deletions
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt new file mode 100644 index 000000000000..27fdc916a434 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 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 + * + * http://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.android.settingslib.spa.framework.theme + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext + +data class SettingsColorScheme( + val background: Color = Color.Unspecified, + val categoryTitle: Color = Color.Unspecified, + val surface: Color = Color.Unspecified, + val surfaceHeader: Color = Color.Unspecified, + val secondaryText: Color = Color.Unspecified, + val primaryContainer: Color = Color.Unspecified, + val onPrimaryContainer: Color = Color.Unspecified, +) + +internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() } + +@Composable +internal fun settingsColorScheme(isDarkTheme: Boolean): SettingsColorScheme { + val context = LocalContext.current + return remember(isDarkTheme) { + when { + isDarkTheme -> dynamicDarkColorScheme(context) + else -> dynamicLightColorScheme(context) + } + } +} + +/** + * Creates a light dynamic color scheme. + * + * Use this function to create a color scheme based off the system wallpaper. If the developer + * changes the wallpaper this color scheme will change accordingly. This dynamic scheme is a + * light theme variant. + * + * @param context The context required to get system resource data. + */ +private fun dynamicLightColorScheme(context: Context): SettingsColorScheme { + val tonalPalette = dynamicTonalPalette(context) + return SettingsColorScheme( + background = tonalPalette.neutral95, + categoryTitle = tonalPalette.primary40, + surface = tonalPalette.neutral99, + surfaceHeader = tonalPalette.neutral90, + secondaryText = tonalPalette.neutralVariant30, + primaryContainer = tonalPalette.primary90, + onPrimaryContainer = tonalPalette.neutral10, + ) +} + +/** + * Creates a dark dynamic color scheme. + * + * Use this function to create a color scheme based off the system wallpaper. If the developer + * changes the wallpaper this color scheme will change accordingly. This dynamic scheme is a dark + * theme variant. + * + * @param context The context required to get system resource data. + */ +private fun dynamicDarkColorScheme(context: Context): SettingsColorScheme { + val tonalPalette = dynamicTonalPalette(context) + return SettingsColorScheme( + background = tonalPalette.neutral10, + categoryTitle = tonalPalette.primary90, + surface = tonalPalette.neutral20, + surfaceHeader = tonalPalette.neutral30, + secondaryText = tonalPalette.neutralVariant80, + primaryContainer = tonalPalette.secondary90, + onPrimaryContainer = tonalPalette.neutral10, + ) +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt index 29998258ed37..e6fa74e34cc8 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt @@ -19,6 +19,8 @@ package com.android.settingslib.spa.framework.theme import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.ReadOnlyComposable /** * The Material 3 Theme for Settings. @@ -26,9 +28,21 @@ import androidx.compose.runtime.Composable @Composable fun SettingsTheme(content: @Composable () -> Unit) { val isDarkTheme = isSystemInDarkTheme() - val colorScheme = materialColorScheme(isDarkTheme) + val settingsColorScheme = settingsColorScheme(isDarkTheme) + val colorScheme = materialColorScheme(isDarkTheme).copy( + background = settingsColorScheme.background, + ) - MaterialTheme(colorScheme = colorScheme) { - content() + CompositionLocalProvider(LocalColorScheme provides settingsColorScheme(isDarkTheme)) { + MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) { + content() + } } } + +object SettingsTheme { + val colorScheme: SettingsColorScheme + @Composable + @ReadOnlyComposable + get() = LocalColorScheme.current +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTonalPalette.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTonalPalette.kt new file mode 100644 index 000000000000..f81f5e734fb4 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTonalPalette.kt @@ -0,0 +1,205 @@ +/* + * Copyright (C) 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 + * + * http://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.android.settingslib.spa.framework.theme + +import android.R +import android.content.Context +import androidx.annotation.ColorRes +import androidx.annotation.DoNotInline +import androidx.compose.ui.graphics.Color + +/** + * Tonal Palette structure in Material. + * + * A tonal palette is comprised of 5 tonal ranges. Each tonal range includes the 13 stops, or + * tonal swatches. + * + * Tonal range names are: + * - Neutral (N) + * - Neutral variant (NV) + * - Primary (P) + * - Secondary (S) + * - Tertiary (T) + */ +internal class SettingsTonalPalette( + // The neutral tonal range from the generated dynamic color palette. + // Ordered from the lightest shade [neutral100] to the darkest shade [neutral0]. + val neutral100: Color, + val neutral99: Color, + val neutral95: Color, + val neutral90: Color, + val neutral80: Color, + val neutral70: Color, + val neutral60: Color, + val neutral50: Color, + val neutral40: Color, + val neutral30: Color, + val neutral20: Color, + val neutral10: Color, + val neutral0: Color, + + // The neutral variant tonal range, sometimes called "neutral 2", from the + // generated dynamic color palette. + // Ordered from the lightest shade [neutralVariant100] to the darkest shade [neutralVariant0]. + val neutralVariant100: Color, + val neutralVariant99: Color, + val neutralVariant95: Color, + val neutralVariant90: Color, + val neutralVariant80: Color, + val neutralVariant70: Color, + val neutralVariant60: Color, + val neutralVariant50: Color, + val neutralVariant40: Color, + val neutralVariant30: Color, + val neutralVariant20: Color, + val neutralVariant10: Color, + val neutralVariant0: Color, + + // The primary tonal range from the generated dynamic color palette. + // Ordered from the lightest shade [primary100] to the darkest shade [primary0]. + val primary100: Color, + val primary99: Color, + val primary95: Color, + val primary90: Color, + val primary80: Color, + val primary70: Color, + val primary60: Color, + val primary50: Color, + val primary40: Color, + val primary30: Color, + val primary20: Color, + val primary10: Color, + val primary0: Color, + + // The secondary tonal range from the generated dynamic color palette. + // Ordered from the lightest shade [secondary100] to the darkest shade [secondary0]. + val secondary100: Color, + val secondary99: Color, + val secondary95: Color, + val secondary90: Color, + val secondary80: Color, + val secondary70: Color, + val secondary60: Color, + val secondary50: Color, + val secondary40: Color, + val secondary30: Color, + val secondary20: Color, + val secondary10: Color, + val secondary0: Color, + + // The tertiary tonal range from the generated dynamic color palette. + // Ordered from the lightest shade [tertiary100] to the darkest shade [tertiary0]. + val tertiary100: Color, + val tertiary99: Color, + val tertiary95: Color, + val tertiary90: Color, + val tertiary80: Color, + val tertiary70: Color, + val tertiary60: Color, + val tertiary50: Color, + val tertiary40: Color, + val tertiary30: Color, + val tertiary20: Color, + val tertiary10: Color, + val tertiary0: Color, +) + +/** Dynamic colors in Material. */ +internal fun dynamicTonalPalette(context: Context) = SettingsTonalPalette( + // The neutral tonal range from the generated dynamic color palette. + neutral100 = ColorResourceHelper.getColor(context, R.color.system_neutral1_0), + neutral99 = ColorResourceHelper.getColor(context, R.color.system_neutral1_10), + neutral95 = ColorResourceHelper.getColor(context, R.color.system_neutral1_50), + neutral90 = ColorResourceHelper.getColor(context, R.color.system_neutral1_100), + neutral80 = ColorResourceHelper.getColor(context, R.color.system_neutral1_200), + neutral70 = ColorResourceHelper.getColor(context, R.color.system_neutral1_300), + neutral60 = ColorResourceHelper.getColor(context, R.color.system_neutral1_400), + neutral50 = ColorResourceHelper.getColor(context, R.color.system_neutral1_500), + neutral40 = ColorResourceHelper.getColor(context, R.color.system_neutral1_600), + neutral30 = ColorResourceHelper.getColor(context, R.color.system_neutral1_700), + neutral20 = ColorResourceHelper.getColor(context, R.color.system_neutral1_800), + neutral10 = ColorResourceHelper.getColor(context, R.color.system_neutral1_900), + neutral0 = ColorResourceHelper.getColor(context, R.color.system_neutral1_1000), + + // The neutral variant tonal range, sometimes called "neutral 2", from the + // generated dynamic color palette. + neutralVariant100 = ColorResourceHelper.getColor(context, R.color.system_neutral2_0), + neutralVariant99 = ColorResourceHelper.getColor(context, R.color.system_neutral2_10), + neutralVariant95 = ColorResourceHelper.getColor(context, R.color.system_neutral2_50), + neutralVariant90 = ColorResourceHelper.getColor(context, R.color.system_neutral2_100), + neutralVariant80 = ColorResourceHelper.getColor(context, R.color.system_neutral2_200), + neutralVariant70 = ColorResourceHelper.getColor(context, R.color.system_neutral2_300), + neutralVariant60 = ColorResourceHelper.getColor(context, R.color.system_neutral2_400), + neutralVariant50 = ColorResourceHelper.getColor(context, R.color.system_neutral2_500), + neutralVariant40 = ColorResourceHelper.getColor(context, R.color.system_neutral2_600), + neutralVariant30 = ColorResourceHelper.getColor(context, R.color.system_neutral2_700), + neutralVariant20 = ColorResourceHelper.getColor(context, R.color.system_neutral2_800), + neutralVariant10 = ColorResourceHelper.getColor(context, R.color.system_neutral2_900), + neutralVariant0 = ColorResourceHelper.getColor(context, R.color.system_neutral2_1000), + + // The primary tonal range from the generated dynamic color palette. + primary100 = ColorResourceHelper.getColor(context, R.color.system_accent1_0), + primary99 = ColorResourceHelper.getColor(context, R.color.system_accent1_10), + primary95 = ColorResourceHelper.getColor(context, R.color.system_accent1_50), + primary90 = ColorResourceHelper.getColor(context, R.color.system_accent1_100), + primary80 = ColorResourceHelper.getColor(context, R.color.system_accent1_200), + primary70 = ColorResourceHelper.getColor(context, R.color.system_accent1_300), + primary60 = ColorResourceHelper.getColor(context, R.color.system_accent1_400), + primary50 = ColorResourceHelper.getColor(context, R.color.system_accent1_500), + primary40 = ColorResourceHelper.getColor(context, R.color.system_accent1_600), + primary30 = ColorResourceHelper.getColor(context, R.color.system_accent1_700), + primary20 = ColorResourceHelper.getColor(context, R.color.system_accent1_800), + primary10 = ColorResourceHelper.getColor(context, R.color.system_accent1_900), + primary0 = ColorResourceHelper.getColor(context, R.color.system_accent1_1000), + + // The secondary tonal range from the generated dynamic color palette. + secondary100 = ColorResourceHelper.getColor(context, R.color.system_accent2_0), + secondary99 = ColorResourceHelper.getColor(context, R.color.system_accent2_10), + secondary95 = ColorResourceHelper.getColor(context, R.color.system_accent2_50), + secondary90 = ColorResourceHelper.getColor(context, R.color.system_accent2_100), + secondary80 = ColorResourceHelper.getColor(context, R.color.system_accent2_200), + secondary70 = ColorResourceHelper.getColor(context, R.color.system_accent2_300), + secondary60 = ColorResourceHelper.getColor(context, R.color.system_accent2_400), + secondary50 = ColorResourceHelper.getColor(context, R.color.system_accent2_500), + secondary40 = ColorResourceHelper.getColor(context, R.color.system_accent2_600), + secondary30 = ColorResourceHelper.getColor(context, R.color.system_accent2_700), + secondary20 = ColorResourceHelper.getColor(context, R.color.system_accent2_800), + secondary10 = ColorResourceHelper.getColor(context, R.color.system_accent2_900), + secondary0 = ColorResourceHelper.getColor(context, R.color.system_accent2_1000), + + // The tertiary tonal range from the generated dynamic color palette. + tertiary100 = ColorResourceHelper.getColor(context, R.color.system_accent3_0), + tertiary99 = ColorResourceHelper.getColor(context, R.color.system_accent3_10), + tertiary95 = ColorResourceHelper.getColor(context, R.color.system_accent3_50), + tertiary90 = ColorResourceHelper.getColor(context, R.color.system_accent3_100), + tertiary80 = ColorResourceHelper.getColor(context, R.color.system_accent3_200), + tertiary70 = ColorResourceHelper.getColor(context, R.color.system_accent3_300), + tertiary60 = ColorResourceHelper.getColor(context, R.color.system_accent3_400), + tertiary50 = ColorResourceHelper.getColor(context, R.color.system_accent3_500), + tertiary40 = ColorResourceHelper.getColor(context, R.color.system_accent3_600), + tertiary30 = ColorResourceHelper.getColor(context, R.color.system_accent3_700), + tertiary20 = ColorResourceHelper.getColor(context, R.color.system_accent3_800), + tertiary10 = ColorResourceHelper.getColor(context, R.color.system_accent3_900), + tertiary0 = ColorResourceHelper.getColor(context, R.color.system_accent3_1000), +) + +private object ColorResourceHelper { + @DoNotInline + fun getColor(context: Context, @ColorRes id: Int): Color { + return Color(context.resources.getColor(id, context.theme)) + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt new file mode 100644 index 000000000000..07f09ba95ca3 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTypography.kt @@ -0,0 +1,144 @@ +/* + * Copyright (C) 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 + * + * http://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.android.settingslib.spa.framework.theme + +import androidx.compose.material3.Typography +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +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.em +import androidx.compose.ui.unit.sp + +private class SettingsTypography { + private val brand = FontFamily.Default + private val plain = FontFamily.Default + + val typography = Typography( + displayLarge = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 57.sp, + lineHeight = 64.sp, + letterSpacing = (-0.2).sp + ), + displayMedium = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 45.sp, + lineHeight = 52.sp, + letterSpacing = 0.0.sp + ), + displaySmall = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 36.sp, + lineHeight = 44.sp, + letterSpacing = 0.0.sp + ), + headlineLarge = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 32.sp, + lineHeight = 40.sp, + letterSpacing = 0.0.sp + ), + headlineMedium = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 28.sp, + lineHeight = 36.sp, + letterSpacing = 0.0.sp + ), + headlineSmall = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 24.sp, + lineHeight = 32.sp, + letterSpacing = 0.0.sp + ), + titleLarge = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.02.em, + ), + titleMedium = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 20.sp, + lineHeight = 24.sp, + letterSpacing = 0.02.em, + ), + titleSmall = TextStyle( + fontFamily = brand, + fontWeight = FontWeight.Normal, + fontSize = 18.sp, + lineHeight = 20.sp, + letterSpacing = 0.02.em, + ), + bodyLarge = TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.01.em, + ), + bodyMedium = TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + ), + bodySmall = TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + ), + labelLarge = TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.01.em, + ), + labelMedium = TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.01.em, + ), + labelSmall = TextStyle( + fontFamily = plain, + fontWeight = FontWeight.Medium, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.01.em, + ), + ) +} + +@Composable +internal fun rememberSettingsTypography(): Typography { + return remember { SettingsTypography().typography } +} |