Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69e557dd authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Add SettingsColors & SettingsTypography"

parents 44878640 3a1d84c1
Loading
Loading
Loading
Loading
+91 −0
Original line number Diff line number Diff line
/*
 * 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,
    )
}
+17 −3
Original line number Diff line number Diff line
@@ -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) {
    CompositionLocalProvider(LocalColorScheme provides settingsColorScheme(isDarkTheme)) {
        MaterialTheme(colorScheme = colorScheme, typography = rememberSettingsTypography()) {
            content()
        }
    }
}

object SettingsTheme {
    val colorScheme: SettingsColorScheme
        @Composable
        @ReadOnlyComposable
        get() = LocalColorScheme.current
}
+205 −0
Original line number Diff line number Diff line
/*
 * 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))
    }
}
+144 −0
Original line number Diff line number Diff line
/*
 * 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 }
}