Merge pull request #7713 from thunderbird/add-material3-compose-theme2
Add Material 3 Compose theme 2
This commit is contained in:
commit
24bacf3e1e
33 changed files with 1248 additions and 15 deletions
|
@ -15,6 +15,8 @@ android {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(projects.core.ui.compose.designsystem)
|
implementation(projects.core.ui.compose.designsystem)
|
||||||
|
|
||||||
|
implementation(projects.core.ui.compose.theme2.k9mail)
|
||||||
|
|
||||||
implementation(libs.androidx.compose.material)
|
implementation(libs.androidx.compose.material)
|
||||||
implementation(libs.androidx.compose.material.icons.extended)
|
implementation(libs.androidx.compose.material.icons.extended)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package app.k9mail.ui.catalog
|
package app.k9mail.ui.catalog
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import app.k9mail.ui.catalog.ui.catalogUiModule
|
import app.k9mail.ui.catalog.di.catalogUiModule
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package app.k9mail.ui.catalog.ui
|
package app.k9mail.ui.catalog.di
|
||||||
|
|
||||||
|
import app.k9mail.ui.catalog.ui.CatalogViewModel
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
|
@ -9,6 +9,9 @@ interface CatalogContract {
|
||||||
) {
|
) {
|
||||||
K9("K-9"),
|
K9("K-9"),
|
||||||
THUNDERBIRD("Thunderbird"),
|
THUNDERBIRD("Thunderbird"),
|
||||||
|
|
||||||
|
// Theme 2
|
||||||
|
THEME_2_K9("K-9 (Material3)"),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ThemeVariant(
|
enum class ThemeVariant(
|
||||||
|
@ -26,8 +29,8 @@ interface CatalogContract {
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed interface Event {
|
sealed interface Event {
|
||||||
object OnThemeChanged : Event
|
data object OnThemeChanged : Event
|
||||||
|
|
||||||
object OnThemeVariantChanged : Event
|
data object OnThemeVariantChanged : Event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,8 @@ import app.k9mail.ui.catalog.ui.CatalogContract.Event
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.Event.OnThemeChanged
|
import app.k9mail.ui.catalog.ui.CatalogContract.Event.OnThemeChanged
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.Event.OnThemeVariantChanged
|
import app.k9mail.ui.catalog.ui.CatalogContract.Event.OnThemeVariantChanged
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.State
|
import app.k9mail.ui.catalog.ui.CatalogContract.State
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.Theme.K9
|
import app.k9mail.ui.catalog.ui.CatalogContract.Theme
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.Theme.THUNDERBIRD
|
import app.k9mail.ui.catalog.ui.CatalogContract.ThemeVariant
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.ThemeVariant.DARK
|
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.ThemeVariant.LIGHT
|
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.ViewModel
|
import app.k9mail.ui.catalog.ui.CatalogContract.ViewModel
|
||||||
|
|
||||||
class CatalogViewModel(
|
class CatalogViewModel(
|
||||||
|
@ -17,18 +15,22 @@ class CatalogViewModel(
|
||||||
override fun event(event: Event) {
|
override fun event(event: Event) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is OnThemeChanged -> {
|
is OnThemeChanged -> {
|
||||||
when (state.value.theme) {
|
updateState { it.copy(theme = selectNextTheme(it.theme)) }
|
||||||
K9 -> updateState { it.copy(theme = THUNDERBIRD) }
|
|
||||||
THUNDERBIRD -> updateState { it.copy(theme = K9) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is OnThemeVariantChanged -> {
|
is OnThemeVariantChanged -> {
|
||||||
when (state.value.themeVariant) {
|
when (state.value.themeVariant) {
|
||||||
LIGHT -> updateState { it.copy(themeVariant = DARK) }
|
ThemeVariant.LIGHT -> updateState { it.copy(themeVariant = ThemeVariant.DARK) }
|
||||||
DARK -> updateState { it.copy(themeVariant = LIGHT) }
|
ThemeVariant.DARK -> updateState { it.copy(themeVariant = ThemeVariant.LIGHT) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun selectNextTheme(currentTheme: Theme): Theme {
|
||||||
|
val themes = Theme.entries
|
||||||
|
val currentThemeIndex = themes.indexOf(currentTheme)
|
||||||
|
val nextThemeIndex = (currentThemeIndex + 1) % themes.size
|
||||||
|
return themes[nextThemeIndex]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package app.k9mail.ui.catalog.ui.common.theme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import app.k9mail.core.ui.compose.theme.K9Theme
|
import app.k9mail.core.ui.compose.theme.K9Theme
|
||||||
import app.k9mail.core.ui.compose.theme.ThunderbirdTheme
|
import app.k9mail.core.ui.compose.theme.ThunderbirdTheme
|
||||||
|
import app.k9mail.core.ui.compose.theme2.k9mail.K9MailTheme2
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.Theme
|
import app.k9mail.ui.catalog.ui.CatalogContract.Theme
|
||||||
import app.k9mail.ui.catalog.ui.CatalogContract.ThemeVariant
|
import app.k9mail.ui.catalog.ui.CatalogContract.ThemeVariant
|
||||||
|
|
||||||
|
@ -17,10 +18,16 @@ fun ThemeSwitch(
|
||||||
themeVariant = themeVariant,
|
themeVariant = themeVariant,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
|
|
||||||
Theme.THUNDERBIRD -> ThunderbirdThemeSwitch(
|
Theme.THUNDERBIRD -> ThunderbirdThemeSwitch(
|
||||||
themeVariant = themeVariant,
|
themeVariant = themeVariant,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Theme.THEME_2_K9 -> K9Theme2Switch(
|
||||||
|
themeVariant = themeVariant,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +41,7 @@ private fun K9ThemeSwitch(
|
||||||
darkTheme = false,
|
darkTheme = false,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
|
|
||||||
ThemeVariant.DARK -> K9Theme(
|
ThemeVariant.DARK -> K9Theme(
|
||||||
darkTheme = true,
|
darkTheme = true,
|
||||||
content = content,
|
content = content,
|
||||||
|
@ -51,9 +59,28 @@ private fun ThunderbirdThemeSwitch(
|
||||||
darkTheme = false,
|
darkTheme = false,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
|
|
||||||
ThemeVariant.DARK -> ThunderbirdTheme(
|
ThemeVariant.DARK -> ThunderbirdTheme(
|
||||||
darkTheme = true,
|
darkTheme = true,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun K9Theme2Switch(
|
||||||
|
themeVariant: ThemeVariant,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
when (themeVariant) {
|
||||||
|
ThemeVariant.LIGHT -> K9MailTheme2(
|
||||||
|
darkTheme = false,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
|
||||||
|
ThemeVariant.DARK -> K9MailTheme2(
|
||||||
|
darkTheme = true,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -790,7 +790,22 @@ style:
|
||||||
Compose:
|
Compose:
|
||||||
CompositionLocalAllowlist:
|
CompositionLocalAllowlist:
|
||||||
active: true
|
active: true
|
||||||
allowedCompositionLocals: [LocalColors, LocalElevations, LocalImages, LocalShapes, LocalSizes, LocalSpacings, LocalActivity]
|
allowedCompositionLocals: [
|
||||||
|
LocalColors,
|
||||||
|
LocalElevations,
|
||||||
|
LocalImages,
|
||||||
|
LocalShapes,
|
||||||
|
LocalSizes,
|
||||||
|
LocalSpacings,
|
||||||
|
LocalActivity,
|
||||||
|
LocalThemeColorScheme,
|
||||||
|
LocalThemeElevations,
|
||||||
|
LocalThemeImages,
|
||||||
|
LocalThemeShapes,
|
||||||
|
LocalThemeSizes,
|
||||||
|
LocalThemeSpacings,
|
||||||
|
LocalThemeTypography
|
||||||
|
]
|
||||||
ContentEmitterReturningValues:
|
ContentEmitterReturningValues:
|
||||||
active: true
|
active: true
|
||||||
ModifierComposable:
|
ModifierComposable:
|
||||||
|
|
15
core/ui/compose/theme2/common/README.md
Normal file
15
core/ui/compose/theme2/common/README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
## Core - UI - Compose - Theme2 - Common
|
||||||
|
|
||||||
|
This provides the common `MainTheme` with dark/light variation support, a wrapper for the Compose Material 3 theme. It supports [CompositionLocal](https://developer.android.com/jetpack/compose/compositionlocal) changes to colors, typography, shapes and adds additionally elevations, sizes, spacings and images.
|
||||||
|
|
||||||
|
To change Material 3 related properties use `MainTheme` instead of `MaterialTheme`:
|
||||||
|
|
||||||
|
- `MainTheme.colors`: Material 3 color scheme
|
||||||
|
- `MainTheme.elevations`: Elevation levels as [defined](https://m3.material.io/styles/elevation/overview) in Material3
|
||||||
|
- `MainTheme.images`: Images used across the theme, e.g. logo
|
||||||
|
- `MainTheme.shapes`: Shapes as [defined](https://m3.material.io/styles/shape/overview) in Material 3
|
||||||
|
- `MainTheme.sizes`: Sizes (smaller, small, medium, large, larger, huge, huger)
|
||||||
|
- `MainTheme.spacings`: Spacings (quarter, half, default, oneHalf, double, triple, quadruple) while default is 8 dp.
|
||||||
|
- `MainTheme.typography`: Material 3 typography
|
||||||
|
|
||||||
|
To use the MainTheme, you need to provide a `ThemeConfig` with your desired colors, typography, shapes, elevations, sizes, spacings and images. The `ThemeConfig` is a data class that holds all the necessary information for the `MainTheme` to work.
|
17
core/ui/compose/theme2/common/build.gradle.kts
Normal file
17
core/ui/compose/theme2/common/build.gradle.kts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
plugins {
|
||||||
|
id(ThunderbirdPlugins.Library.androidCompose)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "app.k9mail.core.ui.compose.theme2"
|
||||||
|
resourcePrefix = "core_ui_theme2"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(projects.core.ui.compose.common)
|
||||||
|
|
||||||
|
implementation(libs.androidx.compose.material3)
|
||||||
|
implementation(libs.androidx.compose.material.icons.extended)
|
||||||
|
|
||||||
|
implementation(libs.androidx.activity)
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MainTheme(
|
||||||
|
themeConfig: ThemeConfig,
|
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
dynamicColor: Boolean = true,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
val themeColorScheme = selectThemeColorScheme(
|
||||||
|
themeConfig = themeConfig,
|
||||||
|
darkTheme = darkTheme,
|
||||||
|
dynamicColor = dynamicColor,
|
||||||
|
)
|
||||||
|
val themeImages = selectThemeImages(
|
||||||
|
themeConfig = themeConfig,
|
||||||
|
darkTheme = darkTheme,
|
||||||
|
)
|
||||||
|
|
||||||
|
SystemBar(
|
||||||
|
darkTheme = darkTheme,
|
||||||
|
colorScheme = themeColorScheme,
|
||||||
|
)
|
||||||
|
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalThemeColorScheme provides themeColorScheme,
|
||||||
|
LocalThemeElevations provides themeConfig.elevations,
|
||||||
|
LocalThemeImages provides themeImages,
|
||||||
|
LocalThemeShapes provides themeConfig.shapes,
|
||||||
|
LocalThemeSizes provides themeConfig.sizes,
|
||||||
|
LocalThemeSpacings provides themeConfig.spacings,
|
||||||
|
LocalThemeTypography provides themeConfig.typography,
|
||||||
|
) {
|
||||||
|
MaterialTheme(
|
||||||
|
colorScheme = themeColorScheme.toMaterial3ColorScheme(),
|
||||||
|
shapes = themeConfig.shapes.toMaterial3Shapes(),
|
||||||
|
typography = themeConfig.typography.toMaterial3Typography(),
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains functions to access the current theme values provided at the call site's position in
|
||||||
|
* the hierarchy.
|
||||||
|
*/
|
||||||
|
object MainTheme {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ColorScheme] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val colors: ThemeColorScheme
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeColorScheme.current
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ThemeElevations] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val elevations: ThemeElevations
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeElevations.current
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ThemeImages] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val images: ThemeImages
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeImages.current
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ThemeShapes] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val shapes: ThemeShapes
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeShapes.current
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ThemeSizes] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val sizes: ThemeSizes
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeSizes.current
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ThemeSpacings] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val spacings: ThemeSpacings
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeSpacings.current
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the current [ThemeTypography] at the call site's position in the hierarchy.
|
||||||
|
*/
|
||||||
|
val typography: ThemeTypography
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalThemeTypography.current
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun selectThemeColorScheme(
|
||||||
|
themeConfig: ThemeConfig,
|
||||||
|
darkTheme: Boolean,
|
||||||
|
dynamicColor: Boolean,
|
||||||
|
): ThemeColorScheme {
|
||||||
|
return when {
|
||||||
|
dynamicColor && supportsDynamicColor() -> {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val colorScheme = if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
|
colorScheme.toThemeColorScheme()
|
||||||
|
}
|
||||||
|
|
||||||
|
darkTheme -> themeConfig.colors.dark
|
||||||
|
else -> themeConfig.colors.light
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supported from Android 12+
|
||||||
|
private fun supportsDynamicColor(): Boolean {
|
||||||
|
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ColorScheme.toThemeColorScheme() = ThemeColorScheme(
|
||||||
|
primary = primary,
|
||||||
|
onPrimary = onPrimary,
|
||||||
|
primaryContainer = primaryContainer,
|
||||||
|
onPrimaryContainer = onPrimaryContainer,
|
||||||
|
|
||||||
|
secondary = secondary,
|
||||||
|
onSecondary = onSecondary,
|
||||||
|
secondaryContainer = secondaryContainer,
|
||||||
|
onSecondaryContainer = onSecondaryContainer,
|
||||||
|
|
||||||
|
tertiary = tertiary,
|
||||||
|
onTertiary = onTertiary,
|
||||||
|
tertiaryContainer = tertiaryContainer,
|
||||||
|
onTertiaryContainer = onTertiaryContainer,
|
||||||
|
|
||||||
|
error = error,
|
||||||
|
onError = onError,
|
||||||
|
errorContainer = errorContainer,
|
||||||
|
onErrorContainer = onErrorContainer,
|
||||||
|
|
||||||
|
surface = surface,
|
||||||
|
onSurface = onSurface,
|
||||||
|
onSurfaceVariant = onSurfaceVariant,
|
||||||
|
surfaceContainerLowest = surfaceContainerLowest,
|
||||||
|
surfaceContainerLow = surfaceContainerLow,
|
||||||
|
surfaceContainer = surfaceContainer,
|
||||||
|
surfaceContainerHigh = surfaceContainerHigh,
|
||||||
|
surfaceContainerHighest = surfaceContainerHighest,
|
||||||
|
|
||||||
|
inverseSurface = inverseSurface,
|
||||||
|
inverseOnSurface = inverseOnSurface,
|
||||||
|
inversePrimary = inversePrimary,
|
||||||
|
|
||||||
|
outline = outline,
|
||||||
|
outlineVariant = outlineVariant,
|
||||||
|
|
||||||
|
surfaceBright = surfaceBright,
|
||||||
|
surfaceDim = surfaceDim,
|
||||||
|
|
||||||
|
scrim = scrim,
|
||||||
|
)
|
|
@ -0,0 +1,12 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun selectThemeImages(
|
||||||
|
themeConfig: ThemeConfig,
|
||||||
|
darkTheme: Boolean,
|
||||||
|
) = when {
|
||||||
|
darkTheme -> themeConfig.images.dark
|
||||||
|
else -> themeConfig.images.light
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SystemBar(
|
||||||
|
darkTheme: Boolean,
|
||||||
|
colorScheme: ThemeColorScheme,
|
||||||
|
) {
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as Activity).window
|
||||||
|
window.statusBarColor = colorScheme.surfaceContainer.toArgb()
|
||||||
|
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme color scheme following Material 3 color roles.
|
||||||
|
*
|
||||||
|
* This supports tone-based Surfaces introduced for Material 3.
|
||||||
|
*
|
||||||
|
* @see: https://m3.material.io/styles/color/roles
|
||||||
|
* @see: https://material.io/blog/tone-based-surface-color-m3
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class ThemeColorScheme(
|
||||||
|
val primary: Color,
|
||||||
|
val onPrimary: Color,
|
||||||
|
val primaryContainer: Color,
|
||||||
|
val onPrimaryContainer: Color,
|
||||||
|
|
||||||
|
val secondary: Color,
|
||||||
|
val onSecondary: Color,
|
||||||
|
val secondaryContainer: Color,
|
||||||
|
val onSecondaryContainer: Color,
|
||||||
|
|
||||||
|
val tertiary: Color,
|
||||||
|
val onTertiary: Color,
|
||||||
|
val tertiaryContainer: Color,
|
||||||
|
val onTertiaryContainer: Color,
|
||||||
|
|
||||||
|
val error: Color,
|
||||||
|
val onError: Color,
|
||||||
|
val errorContainer: Color,
|
||||||
|
val onErrorContainer: Color,
|
||||||
|
|
||||||
|
val surface: Color,
|
||||||
|
val onSurface: Color,
|
||||||
|
val onSurfaceVariant: Color,
|
||||||
|
val surfaceContainerLowest: Color,
|
||||||
|
val surfaceContainerLow: Color,
|
||||||
|
val surfaceContainer: Color,
|
||||||
|
val surfaceContainerHigh: Color,
|
||||||
|
val surfaceContainerHighest: Color,
|
||||||
|
|
||||||
|
val inverseSurface: Color,
|
||||||
|
val inverseOnSurface: Color,
|
||||||
|
val inversePrimary: Color,
|
||||||
|
|
||||||
|
val outline: Color,
|
||||||
|
val outlineVariant: Color,
|
||||||
|
|
||||||
|
val surfaceBright: Color,
|
||||||
|
val surfaceDim: Color,
|
||||||
|
|
||||||
|
val scrim: Color,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a [ThemeColorScheme] to a Material 3 [ColorScheme].
|
||||||
|
*
|
||||||
|
* Note: background, onBackground are deprecated and mapped to surface, onSurface.
|
||||||
|
*/
|
||||||
|
internal fun ThemeColorScheme.toMaterial3ColorScheme(): ColorScheme {
|
||||||
|
return ColorScheme(
|
||||||
|
primary = primary,
|
||||||
|
onPrimary = onPrimary,
|
||||||
|
primaryContainer = primaryContainer,
|
||||||
|
onPrimaryContainer = onPrimaryContainer,
|
||||||
|
|
||||||
|
secondary = secondary,
|
||||||
|
onSecondary = onSecondary,
|
||||||
|
secondaryContainer = secondaryContainer,
|
||||||
|
onSecondaryContainer = onSecondaryContainer,
|
||||||
|
|
||||||
|
tertiary = tertiary,
|
||||||
|
onTertiary = onTertiary,
|
||||||
|
tertiaryContainer = tertiaryContainer,
|
||||||
|
onTertiaryContainer = onTertiaryContainer,
|
||||||
|
|
||||||
|
error = error,
|
||||||
|
onError = onError,
|
||||||
|
errorContainer = errorContainer,
|
||||||
|
onErrorContainer = onErrorContainer,
|
||||||
|
|
||||||
|
surface = surface,
|
||||||
|
onSurface = onSurface,
|
||||||
|
onSurfaceVariant = onSurfaceVariant,
|
||||||
|
|
||||||
|
surfaceContainerLowest = surfaceContainerLowest,
|
||||||
|
surfaceContainerLow = surfaceContainerLow,
|
||||||
|
surfaceContainer = surfaceContainer,
|
||||||
|
surfaceContainerHigh = surfaceContainerHigh,
|
||||||
|
surfaceContainerHighest = surfaceContainerHighest,
|
||||||
|
|
||||||
|
inverseSurface = inverseSurface,
|
||||||
|
inverseOnSurface = inverseOnSurface,
|
||||||
|
inversePrimary = inversePrimary,
|
||||||
|
|
||||||
|
outline = outline,
|
||||||
|
outlineVariant = outlineVariant,
|
||||||
|
|
||||||
|
surfaceBright = surfaceBright,
|
||||||
|
surfaceDim = surfaceDim,
|
||||||
|
|
||||||
|
scrim = scrim,
|
||||||
|
|
||||||
|
// Remapping properties due to changes in Material 3 tone based surface colors
|
||||||
|
// https://material.io/blog/tone-based-surface-color-m3
|
||||||
|
background = surface,
|
||||||
|
onBackground = onSurface,
|
||||||
|
surfaceVariant = surfaceContainerHighest,
|
||||||
|
|
||||||
|
surfaceTint = surfaceContainerHighest,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val LocalThemeColorScheme = staticCompositionLocalOf<ThemeColorScheme> {
|
||||||
|
error("No ThemeColorScheme provided")
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeConfig(
|
||||||
|
val colors: ThemeColorSchemeVariants,
|
||||||
|
val elevations: ThemeElevations,
|
||||||
|
val images: ThemeImageVariants,
|
||||||
|
val shapes: ThemeShapes,
|
||||||
|
val sizes: ThemeSizes,
|
||||||
|
val spacings: ThemeSpacings,
|
||||||
|
val typography: ThemeTypography,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeColorSchemeVariants(
|
||||||
|
val dark: ThemeColorScheme,
|
||||||
|
val light: ThemeColorScheme,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeImageVariants(
|
||||||
|
val dark: ThemeImages,
|
||||||
|
val light: ThemeImages,
|
||||||
|
)
|
|
@ -0,0 +1,29 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elevation values used in the app.
|
||||||
|
*
|
||||||
|
* Material uses six levels of elevation, each with a corresponding dp value. These values are named for their
|
||||||
|
* relative distance above the UI’s surface: 0, +1, +2, +3, +4, and +5. An element’s resting state can be on
|
||||||
|
* levels 0 to +3, while levels +4 and +5 are reserved for user-interacted states such as hover and dragged.
|
||||||
|
*
|
||||||
|
* @see: https://m3.material.io/styles/elevation/tokens
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class ThemeElevations(
|
||||||
|
val level0: Dp = 0.dp,
|
||||||
|
val level1: Dp = 1.dp,
|
||||||
|
val level2: Dp = 3.dp,
|
||||||
|
val level3: Dp = 6.dp,
|
||||||
|
val level4: Dp = 8.dp,
|
||||||
|
val level5: Dp = 12.dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val LocalThemeElevations = staticCompositionLocalOf<ThemeElevations> {
|
||||||
|
error("No ThemeElevations provided")
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeImages(
|
||||||
|
@DrawableRes val logo: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val LocalThemeImages = staticCompositionLocalOf<ThemeImages> {
|
||||||
|
error("No ThemeImages provided")
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.foundation.shape.CornerBasedShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Shapes
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The shapes used in the app.
|
||||||
|
*
|
||||||
|
* The shapes are defined as:
|
||||||
|
*
|
||||||
|
* - None
|
||||||
|
* - ExtraSmall
|
||||||
|
* - Small
|
||||||
|
* - Medium
|
||||||
|
* - Large
|
||||||
|
* - ExtraLarge
|
||||||
|
* - Full
|
||||||
|
*
|
||||||
|
* The default values are based on the Material Design guidelines.
|
||||||
|
*
|
||||||
|
* Shapes None and Full are omitted as None is a RectangleShape and Full is a CircleShape.
|
||||||
|
*
|
||||||
|
* @see: https://m3.material.io/styles/shape/overview
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
data class ThemeShapes(
|
||||||
|
val extraSmall: CornerBasedShape = RoundedCornerShape(4.dp),
|
||||||
|
val small: CornerBasedShape = RoundedCornerShape(8.dp),
|
||||||
|
val medium: CornerBasedShape = RoundedCornerShape(12.dp),
|
||||||
|
val large: CornerBasedShape = RoundedCornerShape(16.dp),
|
||||||
|
val extraLarge: CornerBasedShape = RoundedCornerShape(28.dp),
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the [ThemeShapes] to Material 3 [Shapes].
|
||||||
|
*/
|
||||||
|
internal fun ThemeShapes.toMaterial3Shapes() = Shapes(
|
||||||
|
extraSmall = extraSmall,
|
||||||
|
small = small,
|
||||||
|
medium = medium,
|
||||||
|
large = large,
|
||||||
|
extraLarge = extraLarge,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val LocalThemeShapes = staticCompositionLocalOf<ThemeShapes> {
|
||||||
|
error("No ThemeShapes provided")
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeSizes(
|
||||||
|
val smaller: Dp,
|
||||||
|
val small: Dp,
|
||||||
|
val medium: Dp,
|
||||||
|
val large: Dp,
|
||||||
|
val larger: Dp,
|
||||||
|
val huge: Dp,
|
||||||
|
val huger: Dp,
|
||||||
|
|
||||||
|
val icon: Dp,
|
||||||
|
val largeIcon: Dp,
|
||||||
|
|
||||||
|
val topBarHeight: Dp,
|
||||||
|
val bottomBarHeight: Dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val LocalThemeSizes = staticCompositionLocalOf<ThemeSizes> {
|
||||||
|
error("No ThemeSizes provided")
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeSpacings(
|
||||||
|
val zero: Dp,
|
||||||
|
val quarter: Dp,
|
||||||
|
val half: Dp,
|
||||||
|
val default: Dp,
|
||||||
|
val oneHalf: Dp,
|
||||||
|
val double: Dp,
|
||||||
|
val triple: Dp,
|
||||||
|
val quadruple: Dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val LocalThemeSpacings = staticCompositionLocalOf<ThemeSpacings> {
|
||||||
|
error("No ThemeSpacings provided")
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2
|
||||||
|
|
||||||
|
import androidx.compose.material3.Typography
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ThemeTypography(
|
||||||
|
val displayLarge: TextStyle,
|
||||||
|
val displayMedium: TextStyle,
|
||||||
|
val displaySmall: TextStyle,
|
||||||
|
val headlineLarge: TextStyle,
|
||||||
|
val headlineMedium: TextStyle,
|
||||||
|
val headlineSmall: TextStyle,
|
||||||
|
val titleLarge: TextStyle,
|
||||||
|
val titleMedium: TextStyle,
|
||||||
|
val titleSmall: TextStyle,
|
||||||
|
val bodyLarge: TextStyle,
|
||||||
|
val bodyMedium: TextStyle,
|
||||||
|
val bodySmall: TextStyle,
|
||||||
|
val labelLarge: TextStyle,
|
||||||
|
val labelMedium: TextStyle,
|
||||||
|
val labelSmall: TextStyle,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert [ThemeTypography] to Material 3 [Typography]
|
||||||
|
*/
|
||||||
|
internal fun ThemeTypography.toMaterial3Typography() = Typography(
|
||||||
|
displayLarge = displayLarge,
|
||||||
|
displayMedium = displayMedium,
|
||||||
|
displaySmall = displaySmall,
|
||||||
|
headlineLarge = headlineLarge,
|
||||||
|
headlineMedium = headlineMedium,
|
||||||
|
headlineSmall = headlineSmall,
|
||||||
|
titleLarge = titleLarge,
|
||||||
|
titleMedium = titleMedium,
|
||||||
|
titleSmall = titleSmall,
|
||||||
|
bodyLarge = bodyLarge,
|
||||||
|
bodyMedium = bodyMedium,
|
||||||
|
bodySmall = bodySmall,
|
||||||
|
labelLarge = labelLarge,
|
||||||
|
labelMedium = labelMedium,
|
||||||
|
labelSmall = labelSmall,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val LocalThemeTypography = staticCompositionLocalOf<ThemeTypography> {
|
||||||
|
error("No ThemeTypography provided")
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.default
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeElevations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default values for Material elevation taken from https://m3.material.io/styles/elevation/tokens
|
||||||
|
*/
|
||||||
|
val defaultThemeElevations = ThemeElevations(
|
||||||
|
level0 = 0.dp,
|
||||||
|
level1 = 1.dp,
|
||||||
|
level2 = 3.dp,
|
||||||
|
level3 = 6.dp,
|
||||||
|
level4 = 8.dp,
|
||||||
|
level5 = 12.dp,
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.default
|
||||||
|
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeShapes
|
||||||
|
|
||||||
|
val defaultThemeShapes = ThemeShapes(
|
||||||
|
extraSmall = RoundedCornerShape(4.dp),
|
||||||
|
small = RoundedCornerShape(8.dp),
|
||||||
|
medium = RoundedCornerShape(12.dp),
|
||||||
|
large = RoundedCornerShape(16.dp),
|
||||||
|
extraLarge = RoundedCornerShape(28.dp),
|
||||||
|
)
|
|
@ -0,0 +1,20 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.default
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeSizes
|
||||||
|
|
||||||
|
val defaultThemeSizes = ThemeSizes(
|
||||||
|
smaller = 8.dp,
|
||||||
|
small = 16.dp,
|
||||||
|
medium = 32.dp,
|
||||||
|
large = 64.dp,
|
||||||
|
larger = 128.dp,
|
||||||
|
huge = 256.dp,
|
||||||
|
huger = 384.dp,
|
||||||
|
|
||||||
|
icon = 24.dp,
|
||||||
|
largeIcon = 32.dp,
|
||||||
|
|
||||||
|
topBarHeight = 56.dp,
|
||||||
|
bottomBarHeight = 56.dp,
|
||||||
|
)
|
|
@ -0,0 +1,15 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.default
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeSpacings
|
||||||
|
|
||||||
|
val defaultThemeSpacings = ThemeSpacings(
|
||||||
|
zero = 0.dp,
|
||||||
|
quarter = 2.dp,
|
||||||
|
half = 4.dp,
|
||||||
|
default = 8.dp,
|
||||||
|
oneHalf = 12.dp,
|
||||||
|
double = 16.dp,
|
||||||
|
triple = 24.dp,
|
||||||
|
quadruple = 32.dp,
|
||||||
|
)
|
|
@ -0,0 +1,116 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.default
|
||||||
|
|
||||||
|
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
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeTypography
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
val defaultTypography = ThemeTypography(
|
||||||
|
displayLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 57.sp,
|
||||||
|
lineHeight = 64.sp,
|
||||||
|
letterSpacing = (-0.2).sp,
|
||||||
|
),
|
||||||
|
displayMedium = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 45.sp,
|
||||||
|
lineHeight = 52.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
displaySmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 36.sp,
|
||||||
|
lineHeight = 44.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
headlineLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 32.sp,
|
||||||
|
lineHeight = 40.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
headlineMedium = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 28.sp,
|
||||||
|
lineHeight = 36.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
headlineSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
lineHeight = 32.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
titleLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 22.sp,
|
||||||
|
lineHeight = 28.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
titleMedium = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.2.sp,
|
||||||
|
),
|
||||||
|
titleSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
lineHeight = 20.sp,
|
||||||
|
letterSpacing = 0.1.sp,
|
||||||
|
),
|
||||||
|
bodyLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp,
|
||||||
|
),
|
||||||
|
bodyMedium = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
lineHeight = 20.sp,
|
||||||
|
letterSpacing = 0.2.sp,
|
||||||
|
),
|
||||||
|
bodySmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
lineHeight = 16.sp,
|
||||||
|
letterSpacing = 0.4.sp,
|
||||||
|
),
|
||||||
|
labelLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
lineHeight = 20.sp,
|
||||||
|
letterSpacing = 0.1.sp,
|
||||||
|
),
|
||||||
|
labelMedium = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
lineHeight = 16.sp,
|
||||||
|
letterSpacing = 0.5.sp,
|
||||||
|
),
|
||||||
|
labelSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
lineHeight = 16.sp,
|
||||||
|
letterSpacing = 0.5.sp,
|
||||||
|
),
|
||||||
|
)
|
12
core/ui/compose/theme2/k9mail/README.md
Normal file
12
core/ui/compose/theme2/k9mail/README.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
## Core - UI - Compose - Theme2 - K9Mail
|
||||||
|
|
||||||
|
This provides the `K9MailTheme2` composable, that's setting up the `MainTheme` with K-9 Mail specific colors, typography, shapes, elevations, sizes, spacings and images.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
@Composable
|
||||||
|
fun MyComposable() {
|
||||||
|
K9MailTheme2 {
|
||||||
|
// Your app content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
12
core/ui/compose/theme2/k9mail/build.gradle.kts
Normal file
12
core/ui/compose/theme2/k9mail/build.gradle.kts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
plugins {
|
||||||
|
id(ThunderbirdPlugins.Library.androidCompose)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "app.k9mail.core.ui.compose.theme2.k9mail"
|
||||||
|
resourcePrefix = "core_ui_theme2_k9mail"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(projects.core.ui.compose.theme2.common)
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.k9mail
|
||||||
|
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import app.k9mail.core.ui.compose.theme2.MainTheme
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeColorSchemeVariants
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeConfig
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeImageVariants
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeImages
|
||||||
|
import app.k9mail.core.ui.compose.theme2.default.defaultThemeElevations
|
||||||
|
import app.k9mail.core.ui.compose.theme2.default.defaultThemeShapes
|
||||||
|
import app.k9mail.core.ui.compose.theme2.default.defaultThemeSizes
|
||||||
|
import app.k9mail.core.ui.compose.theme2.default.defaultThemeSpacings
|
||||||
|
import app.k9mail.core.ui.compose.theme2.default.defaultTypography
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun K9MailTheme2(
|
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
dynamicColor: Boolean = false,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
val images = ThemeImages(
|
||||||
|
logo = R.drawable.core_ui_theme2_k9mail_logo,
|
||||||
|
)
|
||||||
|
|
||||||
|
val themeConfig = ThemeConfig(
|
||||||
|
colors = ThemeColorSchemeVariants(
|
||||||
|
dark = darkThemeColorScheme,
|
||||||
|
light = lightThemeColorScheme,
|
||||||
|
),
|
||||||
|
elevations = defaultThemeElevations,
|
||||||
|
images = ThemeImageVariants(
|
||||||
|
light = images,
|
||||||
|
dark = images,
|
||||||
|
),
|
||||||
|
sizes = defaultThemeSizes,
|
||||||
|
spacings = defaultThemeSpacings,
|
||||||
|
shapes = defaultThemeShapes,
|
||||||
|
typography = defaultTypography,
|
||||||
|
)
|
||||||
|
|
||||||
|
MainTheme(
|
||||||
|
themeConfig = themeConfig,
|
||||||
|
darkTheme = darkTheme,
|
||||||
|
dynamicColor = dynamicColor,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.k9mail
|
||||||
|
|
||||||
|
import app.k9mail.core.ui.compose.theme2.ThemeColorScheme
|
||||||
|
|
||||||
|
internal val darkThemeColorScheme = ThemeColorScheme(
|
||||||
|
primary = TonalColorPalette.primary080,
|
||||||
|
onPrimary = TonalColorPalette.primary020,
|
||||||
|
primaryContainer = TonalColorPalette.primary030,
|
||||||
|
onPrimaryContainer = TonalColorPalette.primary090,
|
||||||
|
|
||||||
|
secondary = TonalColorPalette.secondary080,
|
||||||
|
onSecondary = TonalColorPalette.secondary020,
|
||||||
|
secondaryContainer = TonalColorPalette.secondary030,
|
||||||
|
onSecondaryContainer = TonalColorPalette.secondary090,
|
||||||
|
|
||||||
|
tertiary = TonalColorPalette.tertiary080,
|
||||||
|
onTertiary = TonalColorPalette.tertiary020,
|
||||||
|
tertiaryContainer = TonalColorPalette.tertiary030,
|
||||||
|
onTertiaryContainer = TonalColorPalette.tertiary090,
|
||||||
|
|
||||||
|
error = TonalColorPalette.error080,
|
||||||
|
onError = TonalColorPalette.error020,
|
||||||
|
errorContainer = TonalColorPalette.error030,
|
||||||
|
onErrorContainer = TonalColorPalette.error090,
|
||||||
|
|
||||||
|
surface = TonalColorPalette.neutral006,
|
||||||
|
onSurface = TonalColorPalette.neutral090,
|
||||||
|
onSurfaceVariant = TonalColorPalette.neutralVariant080,
|
||||||
|
surfaceContainerLowest = TonalColorPalette.neutral004,
|
||||||
|
surfaceContainerLow = TonalColorPalette.neutral010,
|
||||||
|
surfaceContainer = TonalColorPalette.neutral012,
|
||||||
|
surfaceContainerHigh = TonalColorPalette.neutral017,
|
||||||
|
surfaceContainerHighest = TonalColorPalette.neutral022,
|
||||||
|
|
||||||
|
inverseSurface = TonalColorPalette.neutral090,
|
||||||
|
inverseOnSurface = TonalColorPalette.neutral020,
|
||||||
|
inversePrimary = TonalColorPalette.primary040,
|
||||||
|
|
||||||
|
outline = TonalColorPalette.neutralVariant060,
|
||||||
|
outlineVariant = TonalColorPalette.neutralVariant030,
|
||||||
|
|
||||||
|
surfaceBright = TonalColorPalette.neutral024,
|
||||||
|
surfaceDim = TonalColorPalette.neutral006,
|
||||||
|
|
||||||
|
scrim = TonalColorPalette.neutral000,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val lightThemeColorScheme = ThemeColorScheme(
|
||||||
|
primary = TonalColorPalette.primary040,
|
||||||
|
onPrimary = TonalColorPalette.primary100,
|
||||||
|
primaryContainer = TonalColorPalette.primary090,
|
||||||
|
onPrimaryContainer = TonalColorPalette.primary010,
|
||||||
|
|
||||||
|
secondary = TonalColorPalette.secondary040,
|
||||||
|
onSecondary = TonalColorPalette.secondary100,
|
||||||
|
secondaryContainer = TonalColorPalette.secondary090,
|
||||||
|
onSecondaryContainer = TonalColorPalette.secondary010,
|
||||||
|
|
||||||
|
tertiary = TonalColorPalette.tertiary040,
|
||||||
|
onTertiary = TonalColorPalette.tertiary100,
|
||||||
|
tertiaryContainer = TonalColorPalette.tertiary090,
|
||||||
|
onTertiaryContainer = TonalColorPalette.tertiary010,
|
||||||
|
|
||||||
|
error = TonalColorPalette.error040,
|
||||||
|
onError = TonalColorPalette.error100,
|
||||||
|
errorContainer = TonalColorPalette.error090,
|
||||||
|
onErrorContainer = TonalColorPalette.error010,
|
||||||
|
|
||||||
|
surface = TonalColorPalette.neutral098,
|
||||||
|
onSurface = TonalColorPalette.neutral010,
|
||||||
|
onSurfaceVariant = TonalColorPalette.neutralVariant030,
|
||||||
|
surfaceContainerLowest = TonalColorPalette.neutral100,
|
||||||
|
surfaceContainerLow = TonalColorPalette.neutral096,
|
||||||
|
surfaceContainer = TonalColorPalette.neutral094,
|
||||||
|
surfaceContainerHigh = TonalColorPalette.neutral092,
|
||||||
|
surfaceContainerHighest = TonalColorPalette.neutral090,
|
||||||
|
|
||||||
|
inverseSurface = TonalColorPalette.neutral020,
|
||||||
|
inverseOnSurface = TonalColorPalette.neutral095,
|
||||||
|
inversePrimary = TonalColorPalette.primary080,
|
||||||
|
|
||||||
|
outline = TonalColorPalette.neutralVariant050,
|
||||||
|
outlineVariant = TonalColorPalette.neutralVariant080,
|
||||||
|
|
||||||
|
surfaceBright = TonalColorPalette.neutral098,
|
||||||
|
surfaceDim = TonalColorPalette.neutral087,
|
||||||
|
|
||||||
|
scrim = TonalColorPalette.neutral000,
|
||||||
|
)
|
|
@ -0,0 +1,100 @@
|
||||||
|
package app.k9mail.core.ui.compose.theme2.k9mail
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
internal object TonalColorPalette {
|
||||||
|
val primary010 = Color(color = 0xFF3F001B)
|
||||||
|
val primary020 = Color(color = 0xFF5E112F)
|
||||||
|
val primary030 = Color(color = 0xFF7B2946)
|
||||||
|
val primary000 = Color(color = 0xFF000000)
|
||||||
|
val primary040 = Color(color = 0xFF99405D)
|
||||||
|
val primary050 = Color(color = 0xFFB75876)
|
||||||
|
val primary060 = Color(color = 0xFFD6718F)
|
||||||
|
val primary070 = Color(color = 0xFFF68BAA)
|
||||||
|
val primary080 = Color(color = 0xFFFFB1C5)
|
||||||
|
val primary090 = Color(color = 0xFFFFD9E1)
|
||||||
|
val primary095 = Color(color = 0xFFFFECEF)
|
||||||
|
val primary099 = Color(color = 0xFFFFFBFF)
|
||||||
|
val primary100 = Color(color = 0xFFFFFFFF)
|
||||||
|
|
||||||
|
val secondary000 = Color(color = 0xFF000000)
|
||||||
|
val secondary010 = Color(color = 0xFF2B151B)
|
||||||
|
val secondary020 = Color(color = 0xFF422930)
|
||||||
|
val secondary030 = Color(color = 0xFF5B3F46)
|
||||||
|
val secondary040 = Color(color = 0xFF74565E)
|
||||||
|
val secondary050 = Color(color = 0xFF8F6F76)
|
||||||
|
val secondary060 = Color(color = 0xFFAA8890)
|
||||||
|
val secondary070 = Color(color = 0xFFC6A2AA)
|
||||||
|
val secondary080 = Color(color = 0xFFE3BDC5)
|
||||||
|
val secondary090 = Color(color = 0xFFFFD9E1)
|
||||||
|
val secondary095 = Color(color = 0xFFFFECEF)
|
||||||
|
val secondary099 = Color(color = 0xFFFFFBFF)
|
||||||
|
val secondary100 = Color(color = 0xFFFFFFFF)
|
||||||
|
|
||||||
|
val tertiary000 = Color(color = 0xFF000000)
|
||||||
|
val tertiary010 = Color(color = 0xFF260059)
|
||||||
|
val tertiary020 = Color(color = 0xFF3C1D70)
|
||||||
|
val tertiary030 = Color(color = 0xFF533688)
|
||||||
|
val tertiary040 = Color(color = 0xFF6B4EA2)
|
||||||
|
val tertiary050 = Color(color = 0xFF8567BD)
|
||||||
|
val tertiary060 = Color(color = 0xFF9F81D9)
|
||||||
|
val tertiary070 = Color(color = 0xFFBA9CF6)
|
||||||
|
val tertiary080 = Color(color = 0xFFD3BBFF)
|
||||||
|
val tertiary090 = Color(color = 0xFFEBDDFF)
|
||||||
|
val tertiary095 = Color(color = 0xFFF7EDFF)
|
||||||
|
val tertiary099 = Color(color = 0xFFFFFBFF)
|
||||||
|
val tertiary100 = Color(color = 0xFFFFFFFF)
|
||||||
|
|
||||||
|
val error000 = Color(color = 0xFF000000)
|
||||||
|
val error010 = Color(color = 0xFF410002)
|
||||||
|
val error020 = Color(color = 0xFF690005)
|
||||||
|
val error030 = Color(color = 0xFF93000A)
|
||||||
|
val error040 = Color(color = 0xFFBA1A1A)
|
||||||
|
val error050 = Color(color = 0xFFDE3730)
|
||||||
|
val error060 = Color(color = 0xFFFF5449)
|
||||||
|
val error070 = Color(color = 0xFFFF897D)
|
||||||
|
val error080 = Color(color = 0xFFFFB4AB)
|
||||||
|
val error090 = Color(color = 0xFFFFDAD6)
|
||||||
|
val error095 = Color(color = 0xFFFFEDEA)
|
||||||
|
val error099 = Color(color = 0xFFFFFBFF)
|
||||||
|
val error100 = Color(color = 0xFFFFFFFF)
|
||||||
|
|
||||||
|
val neutral000 = Color(color = 0xFF000000)
|
||||||
|
val neutral004 = Color(color = 0xFF120D0E)
|
||||||
|
val neutral006 = Color(color = 0xFF171213)
|
||||||
|
val neutral010 = Color(color = 0xFF201A1B)
|
||||||
|
val neutral012 = Color(color = 0xFF241E1F)
|
||||||
|
val neutral017 = Color(color = 0xFF2F282A)
|
||||||
|
val neutral020 = Color(color = 0xFF352F30)
|
||||||
|
val neutral022 = Color(color = 0xFF3A3334)
|
||||||
|
val neutral024 = Color(color = 0xFF3E3739)
|
||||||
|
val neutral030 = Color(color = 0xFF4C4546)
|
||||||
|
val neutral040 = Color(color = 0xFF655C5E)
|
||||||
|
val neutral050 = Color(color = 0xFF7E7576)
|
||||||
|
val neutral060 = Color(color = 0xFF988E90)
|
||||||
|
val neutral070 = Color(color = 0xFFB3A9AA)
|
||||||
|
val neutral080 = Color(color = 0xFFCFC4C5)
|
||||||
|
val neutral087 = Color(color = 0xFFE3D7D8)
|
||||||
|
val neutral090 = Color(color = 0xFFECE0E1)
|
||||||
|
val neutral092 = Color(color = 0xFFF1E5E6)
|
||||||
|
val neutral094 = Color(color = 0xFFF7EBEC)
|
||||||
|
val neutral095 = Color(color = 0xFFFAEEEF)
|
||||||
|
val neutral096 = Color(color = 0xFFFDF1F2)
|
||||||
|
val neutral098 = Color(color = 0xFFFFF8F8)
|
||||||
|
val neutral099 = Color(color = 0xFFFFFBFF)
|
||||||
|
val neutral100 = Color(color = 0xFFFFFFFF)
|
||||||
|
|
||||||
|
val neutralVariant000 = Color(color = 0xFF000000)
|
||||||
|
val neutralVariant010 = Color(color = 0xFF24191B)
|
||||||
|
val neutralVariant020 = Color(color = 0xFF3A2D30)
|
||||||
|
val neutralVariant030 = Color(color = 0xFF514346)
|
||||||
|
val neutralVariant040 = Color(color = 0xFF6A5A5E)
|
||||||
|
val neutralVariant050 = Color(color = 0xFF847376)
|
||||||
|
val neutralVariant060 = Color(color = 0xFF9E8C90)
|
||||||
|
val neutralVariant070 = Color(color = 0xFFBAA7AA)
|
||||||
|
val neutralVariant080 = Color(color = 0xFFD6C2C5)
|
||||||
|
val neutralVariant090 = Color(color = 0xFFF3DDE1)
|
||||||
|
val neutralVariant095 = Color(color = 0xFFFFECEF)
|
||||||
|
val neutralVariant099 = Color(color = 0xFFFFFBFF)
|
||||||
|
val neutralVariant100 = Color(color = 0xFFFFFFFF)
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
<!-- TODO: Remove this copy of the app icon and use the app icon instead -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="72dp"
|
||||||
|
android:height="72dp"
|
||||||
|
android:viewportWidth="192"
|
||||||
|
android:viewportHeight="192">
|
||||||
|
<path
|
||||||
|
android:fillColor="#607d8b"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="m32,116v12l25.61,38c2.07,3.59 5.94,6 10.39,6h56c4.46,0 8.32,-2.41 10.39,-6h0.01l25.6,-38v-12z"
|
||||||
|
android:strokeWidth="0.376"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="butt"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#263238"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M64,16h8v28h-8z"
|
||||||
|
android:strokeWidth="5.99999952"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#263238"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M120,16h8v28h-8z"
|
||||||
|
android:strokeWidth="5.99999952"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#4d6570"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m32,127v1l25.61,38c2.07,3.59 5.94,6 10.39,6h56c4.46,0 8.32,-2.41 10.39,-6h0.01l25.6,-38v-1l-25.6,38h-0.01c-2.07,3.59 -5.94,6 -10.39,6h-56c-4.46,0 -8.32,-2.41 -10.39,-6z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#607d8b"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M80,14L80,22A6,6 0,0 1,74 28L50,28A6,6 0,0 1,44 22L44,14A6,6 0,0 1,50 8L74,8A6,6 0,0 1,80 14z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#607d8b"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M148,14L148,22A6,6 0,0 1,142 28L118,28A6,6 0,0 1,112 22L112,14A6,6 0,0 1,118 8L142,8A6,6 0,0 1,148 14z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#4d6570"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m44,21v1c0,3.32 2.68,6 6,6h24c3.32,0 6,-2.68 6,-6v-1c0,3.32 -2.68,6 -6,6h-24c-3.32,0 -6,-2.68 -6,-6z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#4d6570"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m112,21v1c0,3.32 2.68,6 6,6h24c3.32,0 6,-2.68 6,-6v-1c0,3.32 -2.68,6 -6,6h-24c-3.32,0 -6,-2.68 -6,-6z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#8097a2"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m50,8c-3.32,0 -6,2.68 -6,6v1c0,-3.32 2.68,-6 6,-6h24c3.32,0 6,2.68 6,6v-1c0,-3.32 -2.68,-6 -6,-6z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#8097a2"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m118,8c-3.32,0 -6,2.68 -6,6v1c0,-3.32 2.68,-6 6,-6h24c3.32,0 6,2.68 6,6v-1c0,-3.32 -2.68,-6 -6,-6z"
|
||||||
|
android:strokeWidth="0.34016225"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#ff1744"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M172,48L172,116A12,12 0,0 1,160 128L32,128A12,12 0,0 1,20 116L20,48A12,12 0,0 1,32 36L160,36A12,12 0,0 1,172 48z"
|
||||||
|
android:strokeWidth="0.340162"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="m36,52 l60,32 60,-32"
|
||||||
|
android:strokeWidth="6"
|
||||||
|
android:strokeColor="#fbe9e7"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#ff4569"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m32,36c-6.65,0 -12,5.35 -12,12v1c0,-6.65 5.35,-12 12,-12h128c6.65,0 12,5.35 12,12v-1c0,-6.65 -5.35,-12 -12,-12z"
|
||||||
|
android:strokeWidth="0.340162"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#d81a3d"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m20,115v1c0,6.65 5.35,12 12,12h128c6.65,0 12,-5.35 12,-12v-1c0,6.65 -5.35,12 -12,12h-128c-6.65,0 -12,-5.35 -12,-12z"
|
||||||
|
android:strokeWidth="0.340162"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#263238"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M108,158L108,170A6,6 0,0 1,102 176L90,176A6,6 0,0 1,84 170L84,158A6,6 0,0 1,90 152L102,152A6,6 0,0 1,108 158z"
|
||||||
|
android:strokeWidth="0.340162"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#263238"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M96,172m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
|
||||||
|
android:strokeWidth="9"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#37474f"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m90,152c-3.32,0 -6,2.68 -6,6v1c0,-3.32 2.68,-6 6,-6h12c3.32,0 6,2.68 6,6v-1c0,-3.32 -2.68,-6 -6,-6z"
|
||||||
|
android:strokeWidth="0.340162"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#1a252a"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="m84.02,171.43a12,12 0,0 0,-0.02 0.57,12 12,0 0,0 12,12 12,12 0,0 0,12 -12,12 12,0 0,0 -0.02,-0.41 12,12 0,0 1,-11.98 11.41,12 12,0 0,1 -11.98,-11.57z"
|
||||||
|
android:strokeWidth="9"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="miter" />
|
||||||
|
</vector>
|
|
@ -76,6 +76,8 @@ include(
|
||||||
":core:ui:compose:common",
|
":core:ui:compose:common",
|
||||||
":core:ui:compose:designsystem",
|
":core:ui:compose:designsystem",
|
||||||
":core:ui:compose:theme",
|
":core:ui:compose:theme",
|
||||||
|
":core:ui:compose:theme2:common",
|
||||||
|
":core:ui:compose:theme2:k9mail",
|
||||||
":core:ui:compose:testing",
|
":core:ui:compose:testing",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue