Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:56:56 +01:00
parent 75dc487a7a
commit 39c29d175b
6317 changed files with 388324 additions and 2 deletions

View 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.

View file

@ -0,0 +1,18 @@
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.android.material)
implementation(libs.androidx.activity)
}

View file

@ -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
}

View file

@ -0,0 +1,182 @@
package app.k9mail.core.ui.compose.theme2
import android.content.Context
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import com.google.android.material.color.MaterialColors
@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.toDynamicThemeColorScheme(darkTheme, themeConfig.colors)
}
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
}
@Suppress("LongMethod")
private fun ColorScheme.toDynamicThemeColorScheme(
darkTheme: Boolean,
colors: ThemeColorSchemeVariants,
): ThemeColorScheme {
val colorScheme = if (darkTheme) colors.dark else colors.light
val info = colorScheme.info.toHarmonizedColor(primary)
val onInfo = colorScheme.onInfo.toHarmonizedColor(primary)
val infoContainer = colorScheme.infoContainer.toHarmonizedColor(primary)
val onInfoContainer = colorScheme.onInfoContainer.toHarmonizedColor(primary)
val success = colorScheme.success.toHarmonizedColor(primary)
val onSuccess = colorScheme.onSuccess.toHarmonizedColor(primary)
val successContainer = colorScheme.successContainer.toHarmonizedColor(primary)
val onSuccessContainer = colorScheme.onSuccessContainer.toHarmonizedColor(primary)
val warning = colorScheme.warning.toHarmonizedColor(primary)
val onWarning = colorScheme.onWarning.toHarmonizedColor(primary)
val warningContainer = colorScheme.warningContainer.toHarmonizedColor(primary)
val onWarningContainer = colorScheme.onWarningContainer.toHarmonizedColor(primary)
return 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,
info = info,
onInfo = onInfo,
infoContainer = infoContainer,
onInfoContainer = onInfoContainer,
success = success,
onSuccess = onSuccess,
successContainer = successContainer,
onSuccessContainer = onSuccessContainer,
warning = warning,
onWarning = onWarning,
warningContainer = warningContainer,
onWarningContainer = onWarningContainer,
)
}
/**
* The color roles of a theme accent color. They are used to define the main accent color and its complementary colors
* in a Material Design theme.
*
* These roles are used to create a harmonious color scheme that works well together.
*
* The roles are:
* - `accent`: The main accent color.
* - `onAccent`: The color used for text and icons on top of the accent color.
* - `accentContainer`: A container color that complements the accent color.
* - `onAccentContainer`: The color used for text and icons on top of the accent container color.
*
* @param accent The main accent color.
* @param onAccent The color used for text and icons on top of the accent color.
* @param accentContainer A container color that complements the accent color.
* @param onAccentContainer The color used for text and icons on top of the accent container color.
*/
data class ColorRoles(
val accent: Color,
val onAccent: Color,
val accentContainer: Color,
val onAccentContainer: Color,
)
/**
* Returns a harmonized color that is derived from the given color and the target color.
*
* This function uses Material Colors to harmonize the two colors.
*
* @param target The target color to harmonize with.
* @return A new color that is harmonized with the target color.
*/
fun Color.toHarmonizedColor(target: Color) = Color(MaterialColors.harmonize(toArgb(), target.toArgb()))
/**
* Returns a [ColorRoles] object that contains the accent colors derived from the given color.
*
* This function uses Material Colors to retrieve the accent colors based on the provided color.
*
* @param context The context to use for retrieving the color roles.
* @return A [ColorRoles] object containing the accent colors.
*/
fun Color.toColorRoles(context: Context): ColorRoles {
val colorRoles = MaterialColors.getColorRoles(context, this.toArgb())
return ColorRoles(
accent = Color(colorRoles.accent),
onAccent = Color(colorRoles.onAccent),
accentContainer = Color(colorRoles.accentContainer),
onAccentContainer = Color(colorRoles.onAccentContainer),
)
}
/**
* Returns a surface container color that is a composite of the given color and the theme surface container color.
*
* The alpha value is applied to the given color before compositing.
*
* @param alpha The alpha value to apply to the color.
* @return A new color that is a composite of the given color and the theme surface container color.
*/
@Composable
fun Color.toSurfaceContainer(alpha: Float): Color {
val color = copy(alpha = alpha)
return color.compositeOver(MainTheme.colors.surfaceContainer)
}

View file

@ -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
}

View file

@ -0,0 +1,24 @@
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()
window.navigationBarColor = colorScheme.surfaceContainer.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
}
}
}

View file

@ -0,0 +1,144 @@
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
import androidx.compose.material3.LocalContentColor as Material3LocalContentColor
/**
* 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 surfaceDim: Color,
val surface: Color,
val surfaceBright: 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 scrim: Color,
// extra colors
val info: Color,
val onInfo: Color,
val infoContainer: Color,
val onInfoContainer: Color,
val success: Color,
val onSuccess: Color,
val successContainer: Color,
val onSuccessContainer: Color,
val warning: Color,
val onWarning: Color,
val warningContainer: Color,
val onWarningContainer: 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,
surfaceDim = surfaceDim,
surface = surface,
surfaceBright = surfaceBright,
onSurface = onSurface,
onSurfaceVariant = onSurfaceVariant,
surfaceContainerLowest = surfaceContainerLowest,
surfaceContainerLow = surfaceContainerLow,
surfaceContainer = surfaceContainer,
surfaceContainerHigh = surfaceContainerHigh,
surfaceContainerHighest = surfaceContainerHighest,
inverseSurface = inverseSurface,
inverseOnSurface = inverseOnSurface,
inversePrimary = inversePrimary,
outline = outline,
outlineVariant = outlineVariant,
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")
}
/**
* CompositionLocal used to specify the default color for text and icons.
*
* This uses the Material 3 [LocalContentColor] implementation.
*/
val LocalContentColor get() = Material3LocalContentColor

View file

@ -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,
)

View file

@ -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 UIs surface: 0, +1, +2, +3, +4, and +5. An elements 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")
}

View file

@ -0,0 +1,15 @@
package app.k9mail.core.ui.compose.theme2
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
@Suppress("detekt.UnnecessaryAnnotationUseSiteTarget") // https://github.com/detekt/detekt/issues/8212
@Immutable
data class ThemeImages(
@param:DrawableRes val logo: Int,
)
internal val LocalThemeImages = staticCompositionLocalOf<ThemeImages> {
error("No ThemeImages provided")
}

View file

@ -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")
}

View file

@ -0,0 +1,30 @@
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 iconSmall: Dp,
val icon: Dp,
val iconLarge: Dp,
val iconAvatar: Dp,
val topBarHeight: Dp,
val bottomBarHeight: Dp,
val bottomBarHeightWithFab: Dp,
val bannerGlobalHeight: Dp,
)
internal val LocalThemeSizes = staticCompositionLocalOf<ThemeSizes> {
error("No ThemeSizes provided")
}

View file

@ -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")
}

View file

@ -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")
}

View file

@ -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,
)

View file

@ -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),
)

View file

@ -0,0 +1,24 @@
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,
iconSmall = 16.dp,
icon = 24.dp,
iconLarge = 32.dp,
iconAvatar = 48.dp,
topBarHeight = 64.dp,
bottomBarHeight = 80.dp,
bottomBarHeightWithFab = 72.dp,
bannerGlobalHeight = 48.dp,
)

View file

@ -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,
)

View file

@ -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.SemiBold,
fontSize = 14.sp,
lineHeight = 20.sp,
letterSpacing = 0.1.sp,
),
labelMedium = TextStyle(
fontFamily = FontFamily.SansSerif,
fontWeight = FontWeight.Bold,
fontSize = 12.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp,
),
labelSmall = TextStyle(
fontFamily = FontFamily.SansSerif,
fontWeight = FontWeight.Bold,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp,
),
)