Compare commits

...

1 Commits

Author SHA1 Message Date
dccf934172 identity: shared M3 Expressive theme factory + nav slide spec
FloretExpressiveTheme(lightScheme, darkScheme, darkTheme, dynamicColor,
typography) holds the family's theme mechanics — dynamic-colour resolution
(API 31+), system light/dark fallback, and the STANDARD motion scheme — while
each app supplies its own seed-derived colour schemes, so the look stays
per-app and the machinery is shared. rememberNavSlideSpec() shares the fast
spatial nav slide. android-library, Compose-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 12:57:27 +02:00
4 changed files with 111 additions and 0 deletions

39
identity/build.gradle.kts Normal file
View File

@@ -0,0 +1,39 @@
// identity — the family's Material 3 Expressive theme factory + shared motion.
// Holds the theme MECHANICS (dynamic-colour resolution, light/dark, the STANDARD
// motion scheme) and the nav slide spec; each app supplies its own seed-derived
// colour schemes, so the look stays per-app while the machinery is shared.
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "de.jeanlucmakiola.floret.identity"
compileSdk = 37
defaultConfig {
minSdk = 29
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
buildFeatures {
compose = true
}
}
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}
dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.foundation)
implementation(libs.androidx.material3)
}

View File

@@ -0,0 +1,19 @@
package de.jeanlucmakiola.floret.identity
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.IntOffset
/**
* The horizontal slide spec for screen-to-screen navigation: the *fast*
* spring-physics spec from the active motion scheme — snappy with a subtle
* springy settle, rather than a fixed easing curve. Shared so the family's apps
* move the same way. Read in composable scope so the non-composable `NavHost`
* transition lambdas can capture it.
*/
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun rememberNavSlideSpec(): FiniteAnimationSpec<IntOffset> =
MaterialTheme.motionScheme.fastSpatialSpec()

View File

@@ -0,0 +1,52 @@
package de.jeanlucmakiola.floret.identity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialExpressiveTheme
import androidx.compose.material3.MotionScheme
import androidx.compose.material3.Typography
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
/**
* The family's Material 3 Expressive theme factory. Honours system light/dark
* and Material You dynamic colour (API 31+), falling back to the app-supplied
* [lightScheme] / [darkScheme] otherwise. Routes all component + custom motion
* through `MaterialTheme.motionScheme` with the **standard** scheme — spring
* choreography without the overshoot, the family's deliberate motion choice.
*
* The mechanics are shared; the look is not. Each app keeps its identity by
* passing its own hand-tuned, seed-derived [lightScheme] / [darkScheme] and an
* optional [typography]. A thin per-app wrapper (e.g. `AgendulaTheme`) supplies
* those and forwards [darkTheme] / [dynamicColor] from settings.
*/
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun FloretExpressiveTheme(
lightScheme: ColorScheme,
darkScheme: ColorScheme,
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
typography: Typography = Typography(),
content: @Composable () -> Unit,
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val ctx = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(ctx) else dynamicLightColorScheme(ctx)
}
darkTheme -> darkScheme
else -> lightScheme
}
MaterialExpressiveTheme(
colorScheme = colorScheme,
typography = typography,
motionScheme = MotionScheme.standard(),
content = content,
)
}

View File

@@ -33,3 +33,4 @@ rootProject.name = "floret-kit"
include(":core-time") include(":core-time")
include(":core-crash") include(":core-crash")
include(":identity")