feat: add dual-renderer design tokens
This commit is contained in:
@@ -32,11 +32,14 @@ kotlin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":android:core:preferences"))
|
||||
implementation(platform(libs.compose.bom))
|
||||
implementation(libs.compose.ui)
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
implementation(libs.compose.material3)
|
||||
implementation(libs.compose.material.icons.extended)
|
||||
implementation(libs.miuix.ui.android)
|
||||
debugImplementation(libs.compose.ui.tooling)
|
||||
screenshotTestImplementation(libs.compose.screenshot.test)
|
||||
testImplementation(libs.junit)
|
||||
}
|
||||
|
||||
+6
-5
@@ -2,10 +2,11 @@ package com.flagship.abox.manager.designsystem
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxShapeTokens
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeDefaults
|
||||
|
||||
val ABoxShapes = Shapes(
|
||||
small = RoundedCornerShape(8.dp),
|
||||
medium = RoundedCornerShape(16.dp),
|
||||
large = RoundedCornerShape(24.dp),
|
||||
fun ABoxShapes(tokens: ABoxShapeTokens = ABoxThemeDefaults.material3Shapes) = Shapes(
|
||||
small = RoundedCornerShape(tokens.smallCornerRadius),
|
||||
medium = RoundedCornerShape(tokens.mediumCornerRadius),
|
||||
large = RoundedCornerShape(tokens.largeCornerRadius),
|
||||
)
|
||||
|
||||
+143
-26
@@ -1,41 +1,158 @@
|
||||
package com.flagship.abox.manager.designsystem
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import android.os.Build
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.flagship.abox.manager.designsystem.renderer.ABoxRendererAdapters
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxColorTokens
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxSpacing
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeDefaults
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeResolution
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeResolver
|
||||
import com.flagship.abox.manager.preferences.AppThemeMode
|
||||
import com.flagship.abox.manager.preferences.UiPreferences
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Color(0xFF006780),
|
||||
onPrimary = Color.White,
|
||||
primaryContainer = Color(0xFFB8EAFF),
|
||||
onPrimaryContainer = Color(0xFF001F29),
|
||||
secondary = Color(0xFF4D616A),
|
||||
surface = Color(0xFFF8FAFC),
|
||||
background = Color(0xFFF8FAFC),
|
||||
)
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Color(0xFF5DD5F8),
|
||||
onPrimary = Color(0xFF003544),
|
||||
primaryContainer = Color(0xFF004D61),
|
||||
onPrimaryContainer = Color(0xFFB8EAFF),
|
||||
secondary = Color(0xFFB4CBD4),
|
||||
surface = Color(0xFF101416),
|
||||
background = Color(0xFF101416),
|
||||
)
|
||||
val LocalABoxColors = staticCompositionLocalOf { ABoxThemeDefaults.lightColors }
|
||||
val LocalABoxSpacing = staticCompositionLocalOf { ABoxSpacing() }
|
||||
val LocalABoxTypography = staticCompositionLocalOf { ABoxTypography }
|
||||
val LocalABoxShapes = staticCompositionLocalOf { ABoxThemeDefaults.material3Shapes }
|
||||
val LocalABoxRenderer = staticCompositionLocalOf { DesignRenderer.MATERIAL3 }
|
||||
val LocalABoxReducedMotion = staticCompositionLocalOf { false }
|
||||
|
||||
@Composable
|
||||
fun ABoxTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
preferences: UiPreferences,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme,
|
||||
typography = ABoxTypography,
|
||||
shapes = ABoxShapes,
|
||||
val systemInDarkTheme = androidx.compose.foundation.isSystemInDarkTheme()
|
||||
val isDarkTheme = when (preferences.themeMode) {
|
||||
AppThemeMode.SYSTEM -> systemInDarkTheme
|
||||
AppThemeMode.LIGHT -> false
|
||||
AppThemeMode.DARK -> true
|
||||
}
|
||||
val context = LocalContext.current
|
||||
val dynamicTokens = if (preferences.dynamicColorEnabled && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val dynamicColorScheme = if (isDarkTheme) {
|
||||
dynamicDarkColorScheme(context)
|
||||
} else {
|
||||
dynamicLightColorScheme(context)
|
||||
}
|
||||
dynamicColorScheme.toABoxColorTokens()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val resolution = ABoxThemeResolver.resolve(
|
||||
preferences = preferences,
|
||||
systemInDarkTheme = systemInDarkTheme,
|
||||
sdkInt = Build.VERSION.SDK_INT,
|
||||
dynamicColorTokens = dynamicTokens,
|
||||
)
|
||||
val renderer = ABoxRendererAdapters.forRenderer(resolution.renderer)
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalABoxColors provides resolution.colorTokens,
|
||||
LocalABoxSpacing provides ABoxSpacing(),
|
||||
LocalABoxTypography provides ABoxTypography,
|
||||
LocalABoxShapes provides resolution.shapeTokens,
|
||||
LocalABoxRenderer provides resolution.renderer,
|
||||
LocalABoxReducedMotion provides false,
|
||||
) {
|
||||
renderer.Render(
|
||||
resolution = resolution,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ABoxTheme(
|
||||
darkTheme: Boolean = androidx.compose.foundation.isSystemInDarkTheme(),
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
ABoxTheme(
|
||||
preferences = UiPreferences(
|
||||
themeMode = if (darkTheme) AppThemeMode.DARK else AppThemeMode.LIGHT,
|
||||
dynamicColorEnabled = false,
|
||||
),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
internal fun materialColorScheme(resolution: ABoxThemeResolution): ColorScheme {
|
||||
val colors = resolution.colorTokens
|
||||
val onPrimary = if (resolution.isDarkTheme) Color(0xFF003544) else Color.White
|
||||
val onSurface = if (resolution.isDarkTheme) Color(0xFFE0E3E5) else Color(0xFF191C1E)
|
||||
val onSurfaceVariant = if (resolution.isDarkTheme) Color(0xFFC0C8CC) else Color(0xFF40484C)
|
||||
val primaryContainer = colors.primary.copy(alpha = if (resolution.isDarkTheme) 0.35f else 0.20f)
|
||||
val secondaryContainer = colors.surfaceContainer
|
||||
|
||||
return if (resolution.isDarkTheme) {
|
||||
darkColorScheme(
|
||||
primary = colors.primary,
|
||||
onPrimary = onPrimary,
|
||||
primaryContainer = primaryContainer,
|
||||
onPrimaryContainer = colors.primary,
|
||||
secondary = colors.pending,
|
||||
onSecondary = Color(0xFF3F2E00),
|
||||
secondaryContainer = secondaryContainer,
|
||||
onSecondaryContainer = onSurface,
|
||||
tertiary = colors.success,
|
||||
onTertiary = Color(0xFF00391E),
|
||||
surface = colors.surface,
|
||||
onSurface = onSurface,
|
||||
surfaceVariant = colors.surfaceContainer,
|
||||
onSurfaceVariant = onSurfaceVariant,
|
||||
background = colors.surface,
|
||||
onBackground = onSurface,
|
||||
outline = colors.outline,
|
||||
error = colors.error,
|
||||
onError = Color(0xFF690005),
|
||||
)
|
||||
} else {
|
||||
lightColorScheme(
|
||||
primary = colors.primary,
|
||||
onPrimary = onPrimary,
|
||||
primaryContainer = primaryContainer,
|
||||
onPrimaryContainer = Color(0xFF001F29),
|
||||
secondary = colors.pending,
|
||||
onSecondary = Color.White,
|
||||
secondaryContainer = secondaryContainer,
|
||||
onSecondaryContainer = onSurface,
|
||||
tertiary = colors.success,
|
||||
onTertiary = Color.White,
|
||||
surface = colors.surface,
|
||||
onSurface = onSurface,
|
||||
surfaceVariant = colors.surfaceContainer,
|
||||
onSurfaceVariant = onSurfaceVariant,
|
||||
background = colors.surface,
|
||||
onBackground = onSurface,
|
||||
outline = colors.outline,
|
||||
error = colors.error,
|
||||
onError = Color.White,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ColorScheme.toABoxColorTokens() = ABoxColorTokens(
|
||||
primary = primary,
|
||||
surface = surface,
|
||||
surfaceContainer = surfaceContainer,
|
||||
outline = outline,
|
||||
success = tertiary,
|
||||
warning = secondary,
|
||||
error = error,
|
||||
offline = outline,
|
||||
pending = secondary,
|
||||
deviceSocket = primary,
|
||||
deviceSensor = tertiary,
|
||||
deviceInfrared = secondary,
|
||||
)
|
||||
|
||||
+1
@@ -2,4 +2,5 @@ package com.flagship.abox.manager.designsystem
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
|
||||
/** Default typography supplied through [LocalABoxTypography]. */
|
||||
val ABoxTypography = Typography()
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.flagship.abox.manager.designsystem.renderer
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeResolution
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
|
||||
internal interface ABoxRendererAdapter {
|
||||
@Composable
|
||||
fun Render(
|
||||
resolution: ABoxThemeResolution,
|
||||
content: @Composable () -> Unit,
|
||||
)
|
||||
}
|
||||
|
||||
internal object ABoxRendererAdapters {
|
||||
fun forRenderer(renderer: DesignRenderer): ABoxRendererAdapter = when (renderer) {
|
||||
DesignRenderer.MATERIAL3 -> Material3RendererAdapter
|
||||
DesignRenderer.MIUIX -> MiuixRendererAdapter
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.flagship.abox.manager.designsystem.renderer
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.flagship.abox.manager.designsystem.ABoxShapes
|
||||
import com.flagship.abox.manager.designsystem.ABoxTypography
|
||||
import com.flagship.abox.manager.designsystem.materialColorScheme
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeResolution
|
||||
|
||||
object Material3RendererAdapter : ABoxRendererAdapter {
|
||||
@Composable
|
||||
override fun Render(
|
||||
resolution: ABoxThemeResolution,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = materialColorScheme(resolution),
|
||||
typography = ABoxTypography,
|
||||
shapes = ABoxShapes(resolution.shapeTokens),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.flagship.abox.manager.designsystem.renderer
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.flagship.abox.manager.designsystem.tokens.ABoxThemeResolution
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import top.yukonga.miuix.kmp.theme.darkColorScheme
|
||||
import top.yukonga.miuix.kmp.theme.lightColorScheme
|
||||
|
||||
internal object MiuixRendererAdapter : ABoxRendererAdapter {
|
||||
@Composable
|
||||
override fun Render(
|
||||
resolution: ABoxThemeResolution,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val colors = if (resolution.isDarkTheme) darkColorScheme() else lightColorScheme()
|
||||
MiuixTheme(
|
||||
colors = colors,
|
||||
) {
|
||||
Material3RendererAdapter.Render(
|
||||
resolution = resolution,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package com.flagship.abox.manager.designsystem.tokens
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.flagship.abox.manager.preferences.AppThemeMode
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
import com.flagship.abox.manager.preferences.UiPreferences
|
||||
|
||||
@Immutable
|
||||
data class ABoxColorTokens(
|
||||
val primary: Color,
|
||||
val surface: Color,
|
||||
val surfaceContainer: Color,
|
||||
val outline: Color,
|
||||
val success: Color,
|
||||
val warning: Color,
|
||||
val error: Color,
|
||||
val offline: Color,
|
||||
val pending: Color,
|
||||
val deviceSocket: Color,
|
||||
val deviceSensor: Color,
|
||||
val deviceInfrared: Color,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class ABoxSpacing(
|
||||
val dp4: Dp = 4.dp,
|
||||
val dp8: Dp = 8.dp,
|
||||
val dp12: Dp = 12.dp,
|
||||
val dp16: Dp = 16.dp,
|
||||
val dp20: Dp = 20.dp,
|
||||
val dp24: Dp = 24.dp,
|
||||
val dp32: Dp = 32.dp,
|
||||
val minimumTouchTarget: Dp = 48.dp,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class ABoxComponentState(
|
||||
val enabled: Boolean = true,
|
||||
val pending: Boolean = false,
|
||||
val offline: Boolean = false,
|
||||
val dangerous: Boolean = false,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class ABoxShapeTokens(
|
||||
val smallCornerRadius: Dp,
|
||||
val mediumCornerRadius: Dp,
|
||||
val largeCornerRadius: Dp,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
data class ABoxThemeResolution(
|
||||
val isDarkTheme: Boolean,
|
||||
val colorTokens: ABoxColorTokens,
|
||||
val shapeTokens: ABoxShapeTokens,
|
||||
val blurEnabled: Boolean,
|
||||
val renderer: DesignRenderer,
|
||||
)
|
||||
|
||||
object ABoxThemeDefaults {
|
||||
val lightColors = ABoxColorTokens(
|
||||
primary = Color(0xFF006780),
|
||||
surface = Color(0xFFF8FAFC),
|
||||
surfaceContainer = Color(0xFFE2E8F0),
|
||||
outline = Color(0xFF70797D),
|
||||
success = Color(0xFF1B7F4B),
|
||||
warning = Color(0xFF8A5800),
|
||||
error = Color(0xFFBA1A1A),
|
||||
offline = Color(0xFF5F6B72),
|
||||
pending = Color(0xFF8A5800),
|
||||
deviceSocket = Color(0xFF006E90),
|
||||
deviceSensor = Color(0xFF476B23),
|
||||
deviceInfrared = Color(0xFF77536F),
|
||||
)
|
||||
val darkColors = ABoxColorTokens(
|
||||
primary = Color(0xFF5DD5F8),
|
||||
surface = Color(0xFF101416),
|
||||
surfaceContainer = Color(0xFF1F292D),
|
||||
outline = Color(0xFF8A969B),
|
||||
success = Color(0xFF7EDFA7),
|
||||
warning = Color(0xFFFFB95B),
|
||||
error = Color(0xFFFFB4AB),
|
||||
offline = Color(0xFFBFC9CD),
|
||||
pending = Color(0xFFFFB95B),
|
||||
deviceSocket = Color(0xFF5DD5F8),
|
||||
deviceSensor = Color(0xFFAFD67C),
|
||||
deviceInfrared = Color(0xFFE6B5D6),
|
||||
)
|
||||
val material3Shapes = ABoxShapeTokens(
|
||||
smallCornerRadius = 8.dp,
|
||||
mediumCornerRadius = 16.dp,
|
||||
largeCornerRadius = 24.dp,
|
||||
)
|
||||
val miuixShapes = ABoxShapeTokens(
|
||||
smallCornerRadius = 12.dp,
|
||||
mediumCornerRadius = 20.dp,
|
||||
largeCornerRadius = 28.dp,
|
||||
)
|
||||
}
|
||||
|
||||
object ABoxThemeResolver {
|
||||
fun resolve(
|
||||
preferences: UiPreferences,
|
||||
systemInDarkTheme: Boolean,
|
||||
sdkInt: Int,
|
||||
dynamicColorTokens: ABoxColorTokens?,
|
||||
): ABoxThemeResolution {
|
||||
val isDarkTheme = when (preferences.themeMode) {
|
||||
AppThemeMode.SYSTEM -> systemInDarkTheme
|
||||
AppThemeMode.LIGHT -> false
|
||||
AppThemeMode.DARK -> true
|
||||
}
|
||||
val brandTokens = if (isDarkTheme) {
|
||||
ABoxThemeDefaults.darkColors
|
||||
} else {
|
||||
ABoxThemeDefaults.lightColors
|
||||
}
|
||||
val colorTokens = if (preferences.dynamicColorEnabled && sdkInt >= 31 && dynamicColorTokens != null) {
|
||||
dynamicColorTokens
|
||||
} else {
|
||||
brandTokens
|
||||
}
|
||||
val shapeTokens = when (preferences.renderer) {
|
||||
DesignRenderer.MATERIAL3 -> ABoxThemeDefaults.material3Shapes
|
||||
DesignRenderer.MIUIX -> ABoxThemeDefaults.miuixShapes
|
||||
}
|
||||
|
||||
return ABoxThemeResolution(
|
||||
isDarkTheme = isDarkTheme,
|
||||
colorTokens = colorTokens,
|
||||
shapeTokens = shapeTokens,
|
||||
blurEnabled = preferences.blurEnabled && preferences.renderer == DesignRenderer.MIUIX,
|
||||
renderer = preferences.renderer,
|
||||
)
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -4,10 +4,21 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.android.tools.screenshot.PreviewTest
|
||||
import com.flagship.abox.manager.preferences.AppThemeMode
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
import com.flagship.abox.manager.preferences.UiPreferences
|
||||
|
||||
@PreviewTest
|
||||
@Preview
|
||||
@Composable
|
||||
fun DesignSystemSmokePreview() {
|
||||
ABoxTheme(darkTheme = false) { Text("截图基线") }
|
||||
ABoxTheme(
|
||||
preferences = UiPreferences(
|
||||
renderer = DesignRenderer.MATERIAL3,
|
||||
themeMode = AppThemeMode.LIGHT,
|
||||
dynamicColorEnabled = false,
|
||||
),
|
||||
) {
|
||||
Text("截图基线")
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.flagship.abox.manager.designsystem.renderer
|
||||
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Test
|
||||
|
||||
class ABoxRendererAdapterTest {
|
||||
@Test
|
||||
fun selectsMaterial3AndMiuixAdaptersFromRendererPreference() {
|
||||
assertSame(
|
||||
Material3RendererAdapter,
|
||||
ABoxRendererAdapters.forRenderer(DesignRenderer.MATERIAL3),
|
||||
)
|
||||
assertSame(
|
||||
MiuixRendererAdapter,
|
||||
ABoxRendererAdapters.forRenderer(DesignRenderer.MIUIX),
|
||||
)
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.flagship.abox.manager.designsystem.tokens
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.flagship.abox.manager.preferences.AppThemeMode
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
import com.flagship.abox.manager.preferences.UiPreferences
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
|
||||
class ABoxThemeResolverTest {
|
||||
@Test
|
||||
fun systemLightAndDarkResolveDeterministically() {
|
||||
val light = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(themeMode = AppThemeMode.SYSTEM),
|
||||
systemInDarkTheme = false,
|
||||
sdkInt = 30,
|
||||
dynamicColorTokens = null,
|
||||
)
|
||||
val dark = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(themeMode = AppThemeMode.SYSTEM),
|
||||
systemInDarkTheme = true,
|
||||
sdkInt = 30,
|
||||
dynamicColorTokens = null,
|
||||
)
|
||||
|
||||
assertFalse(light.isDarkTheme)
|
||||
assertEquals(ABoxThemeDefaults.lightColors, light.colorTokens)
|
||||
assertEquals(ABoxThemeDefaults.darkColors, dark.colorTokens)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dynamicColorDisabledUsesBrandTokens() {
|
||||
val resolution = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(
|
||||
themeMode = AppThemeMode.LIGHT,
|
||||
dynamicColorEnabled = false,
|
||||
),
|
||||
systemInDarkTheme = false,
|
||||
sdkInt = 31,
|
||||
dynamicColorTokens = dynamicTokens,
|
||||
)
|
||||
|
||||
assertEquals(ABoxThemeDefaults.lightColors, resolution.colorTokens)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pre31DynamicColorFallsBackToBrandTokens() {
|
||||
val resolution = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(
|
||||
themeMode = AppThemeMode.DARK,
|
||||
dynamicColorEnabled = true,
|
||||
),
|
||||
systemInDarkTheme = false,
|
||||
sdkInt = 30,
|
||||
dynamicColorTokens = dynamicTokens,
|
||||
)
|
||||
|
||||
assertEquals(ABoxThemeDefaults.darkColors, resolution.colorTokens)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun blurDisabledResolvesOpaqueSurface() {
|
||||
val resolution = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(blurEnabled = false),
|
||||
systemInDarkTheme = false,
|
||||
sdkInt = 31,
|
||||
dynamicColorTokens = null,
|
||||
)
|
||||
|
||||
assertFalse(resolution.blurEnabled)
|
||||
assertEquals(1f, resolution.colorTokens.surface.alpha)
|
||||
assertEquals(1f, resolution.colorTokens.surfaceContainer.alpha)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rendererChangesShapeButNotSemanticStateRoles() {
|
||||
val material = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(renderer = DesignRenderer.MATERIAL3),
|
||||
systemInDarkTheme = false,
|
||||
sdkInt = 31,
|
||||
dynamicColorTokens = null,
|
||||
)
|
||||
val miuix = ABoxThemeResolver.resolve(
|
||||
preferences = UiPreferences(renderer = DesignRenderer.MIUIX),
|
||||
systemInDarkTheme = false,
|
||||
sdkInt = 31,
|
||||
dynamicColorTokens = null,
|
||||
)
|
||||
|
||||
assertEquals(material.colorTokens.success, miuix.colorTokens.success)
|
||||
assertEquals(material.colorTokens.warning, miuix.colorTokens.warning)
|
||||
assertEquals(material.colorTokens.error, miuix.colorTokens.error)
|
||||
assertEquals(material.colorTokens.offline, miuix.colorTokens.offline)
|
||||
assertEquals(material.colorTokens.pending, miuix.colorTokens.pending)
|
||||
assertNotEquals(material.shapeTokens, miuix.shapeTokens)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val dynamicTokens = ABoxColorTokens(
|
||||
primary = Color(0xFF111111),
|
||||
surface = Color(0xFF222222),
|
||||
surfaceContainer = Color(0xFF333333),
|
||||
outline = Color(0xFF444444),
|
||||
success = Color(0xFF555555),
|
||||
warning = Color(0xFF666666),
|
||||
error = Color(0xFF777777),
|
||||
offline = Color(0xFF888888),
|
||||
pending = Color(0xFF999999),
|
||||
deviceSocket = Color(0xFFAAAAAA),
|
||||
deviceSensor = Color(0xFFBBBBBB),
|
||||
deviceInfrared = Color(0xFFCCCCCC),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user