fix(ui): stabilize theme and navigation behavior
This commit is contained in:
@@ -38,6 +38,7 @@ dependencies {
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
implementation(libs.compose.material3)
|
||||
implementation(libs.compose.material.icons.extended)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.miuix.ui.android)
|
||||
debugImplementation(libs.compose.ui.tooling)
|
||||
screenshotTestImplementation(libs.compose.screenshot.test)
|
||||
|
||||
+18
@@ -1,5 +1,7 @@
|
||||
package com.flagship.abox.manager.designsystem
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -45,6 +47,9 @@ import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -677,3 +682,16 @@ fun RowScope.ABoxNavigationBarItem(
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ABoxBackLayer(
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
BackHandler(enabled = enabled, onBack = onBack)
|
||||
Box(modifier = modifier.fillMaxSize()) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ internal fun ABoxThemeContent(
|
||||
LocalABoxBlurEnabled provides resolution.blurEnabled,
|
||||
LocalABoxNavigationPresentation provides preferences.navigationPresentation,
|
||||
LocalABoxLiquidGlassEnabled provides preferences.liquidGlassEnabled,
|
||||
LocalABoxPredictiveBackEnabled provides preferences.predictiveBackEnabled,
|
||||
LocalABoxPredictiveBackEnabled provides false,
|
||||
) {
|
||||
renderer.Render(
|
||||
resolution = resolution,
|
||||
|
||||
+91
-9
@@ -2,10 +2,13 @@ package com.flagship.abox.manager.designsystem.tokens
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.lerp
|
||||
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.AccentPreference
|
||||
import com.flagship.abox.manager.preferences.ColorStandard
|
||||
import com.flagship.abox.manager.preferences.ColorStyle
|
||||
import com.flagship.abox.manager.preferences.DesignRenderer
|
||||
import com.flagship.abox.manager.preferences.UiPreferences
|
||||
|
||||
@@ -122,7 +125,13 @@ object ABoxThemeResolver {
|
||||
val colorTokens = if (preferences.dynamicColorEnabled && sdkInt >= 31 && dynamicColorTokens != null) {
|
||||
dynamicColorTokens
|
||||
} else {
|
||||
brandTokens.withAccent(preferences.accentPreference, isDarkTheme)
|
||||
ABoxAccentPalette.resolve(
|
||||
base = brandTokens,
|
||||
accent = preferences.accentPreference,
|
||||
style = preferences.colorStyle,
|
||||
standard = preferences.colorStandard,
|
||||
dark = isDarkTheme,
|
||||
)
|
||||
}
|
||||
val shapeTokens = when (preferences.renderer) {
|
||||
DesignRenderer.MATERIAL3 -> ABoxThemeDefaults.material3Shapes
|
||||
@@ -139,13 +148,86 @@ object ABoxThemeResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ABoxColorTokens.withAccent(accent: AccentPreference, dark: Boolean): ABoxColorTokens {
|
||||
val selected = when (accent) {
|
||||
AccentPreference.BLUE -> if (dark) Color(0xFF9CCAFF) else Color(0xFF385F9D)
|
||||
AccentPreference.GREEN -> if (dark) Color(0xFF7EDFA7) else Color(0xFF247A4B)
|
||||
AccentPreference.AMBER -> if (dark) Color(0xFFFFC46B) else Color(0xFF8A5800)
|
||||
AccentPreference.ROSE -> if (dark) Color(0xFFFFB1C1) else Color(0xFFA43C59)
|
||||
AccentPreference.VIOLET -> if (dark) Color(0xFFD4BBFF) else Color(0xFF6D52A2)
|
||||
object ABoxAccentPalette {
|
||||
fun preview(
|
||||
accent: AccentPreference,
|
||||
style: ColorStyle,
|
||||
standard: ColorStandard,
|
||||
dark: Boolean,
|
||||
): Color = resolve(
|
||||
base = if (dark) ABoxThemeDefaults.darkColors else ABoxThemeDefaults.lightColors,
|
||||
accent = accent,
|
||||
style = style,
|
||||
standard = standard,
|
||||
dark = dark,
|
||||
).primary
|
||||
|
||||
fun resolve(
|
||||
base: ABoxColorTokens,
|
||||
accent: AccentPreference,
|
||||
style: ColorStyle,
|
||||
standard: ColorStandard,
|
||||
dark: Boolean,
|
||||
): ABoxColorTokens {
|
||||
val source = source(accent, dark)
|
||||
val primary = when (style) {
|
||||
ColorStyle.TONAL_SPOT -> lerp(source, base.surface, if (dark) 0.08f else 0.12f)
|
||||
ColorStyle.EXPRESSIVE -> expressive(accent, dark)
|
||||
ColorStyle.FIDELITY -> source
|
||||
}
|
||||
val deviceSensor = when (style) {
|
||||
ColorStyle.EXPRESSIVE -> expressiveSensor(accent, dark)
|
||||
ColorStyle.FIDELITY -> lerp(source, base.success, 0.38f)
|
||||
ColorStyle.TONAL_SPOT -> base.deviceSensor
|
||||
}
|
||||
val deviceInfrared = when (style) {
|
||||
ColorStyle.EXPRESSIVE -> expressiveInfrared(accent, dark)
|
||||
ColorStyle.FIDELITY -> lerp(source, base.deviceInfrared, 0.46f)
|
||||
ColorStyle.TONAL_SPOT -> base.deviceInfrared
|
||||
}
|
||||
val styled = base.copy(
|
||||
primary = primary,
|
||||
deviceSocket = primary,
|
||||
deviceSensor = deviceSensor,
|
||||
deviceInfrared = deviceInfrared,
|
||||
)
|
||||
return when (standard) {
|
||||
ColorStandard.SPEC_2021 -> styled
|
||||
ColorStandard.SPEC_2025 -> styled.copy(
|
||||
surface = if (dark) Color(0xFF0C1114) else Color(0xFFFAF9FC),
|
||||
surfaceContainer = if (dark) Color(0xFF242C30) else Color(0xFFE9E8EE),
|
||||
outline = if (dark) Color(0xFFA7B2B7) else Color(0xFF596267),
|
||||
primary = lerp(primary, if (dark) Color.White else Color.Black, 0.08f),
|
||||
deviceSocket = lerp(primary, if (dark) Color.White else Color.Black, 0.08f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun source(accent: AccentPreference, dark: Boolean): Color = when (accent) {
|
||||
AccentPreference.BLUE -> if (dark) Color(0xFF9CCAFF) else Color(0xFF4F6FA9)
|
||||
AccentPreference.GREEN -> if (dark) Color(0xFF7EDFA7) else Color(0xFF2F7D57)
|
||||
AccentPreference.AMBER -> if (dark) Color(0xFFFFC46B) else Color(0xFFA66700)
|
||||
AccentPreference.ROSE -> if (dark) Color(0xFFFFB1C1) else Color(0xFFA94C68)
|
||||
AccentPreference.VIOLET -> if (dark) Color(0xFFD4BBFF) else Color(0xFF7659A8)
|
||||
}
|
||||
|
||||
private fun expressive(accent: AccentPreference, dark: Boolean): Color = when (accent) {
|
||||
AccentPreference.BLUE -> if (dark) Color(0xFF72D6FF) else Color(0xFF006B91)
|
||||
AccentPreference.GREEN -> if (dark) Color(0xFF69E6B1) else Color(0xFF007A54)
|
||||
AccentPreference.AMBER -> if (dark) Color(0xFFFFC24B) else Color(0xFF9A5C00)
|
||||
AccentPreference.ROSE -> if (dark) Color(0xFFFFA8C4) else Color(0xFFB12F62)
|
||||
AccentPreference.VIOLET -> if (dark) Color(0xFFC9B5FF) else Color(0xFF7048B8)
|
||||
}
|
||||
|
||||
private fun expressiveSensor(accent: AccentPreference, dark: Boolean): Color = when (accent) {
|
||||
AccentPreference.BLUE, AccentPreference.VIOLET -> if (dark) Color(0xFF78DFA2) else Color(0xFF26764A)
|
||||
AccentPreference.GREEN, AccentPreference.AMBER -> if (dark) Color(0xFF79D6F3) else Color(0xFF006985)
|
||||
AccentPreference.ROSE -> if (dark) Color(0xFFFFC45F) else Color(0xFF8B5B00)
|
||||
}
|
||||
|
||||
private fun expressiveInfrared(accent: AccentPreference, dark: Boolean): Color = when (accent) {
|
||||
AccentPreference.BLUE, AccentPreference.GREEN -> if (dark) Color(0xFFD1B8FF) else Color(0xFF7453A5)
|
||||
AccentPreference.AMBER, AccentPreference.ROSE -> if (dark) Color(0xFF9FCBFF) else Color(0xFF38639A)
|
||||
AccentPreference.VIOLET -> if (dark) Color(0xFFFFB0C7) else Color(0xFFA43E62)
|
||||
}
|
||||
return copy(primary = selected, deviceSocket = selected)
|
||||
}
|
||||
|
||||
+40
-4
@@ -26,8 +26,26 @@ class ABoxThemeResolverTest {
|
||||
)
|
||||
|
||||
assertFalse(light.isDarkTheme)
|
||||
assertEquals(ABoxThemeDefaults.lightColors, light.colorTokens)
|
||||
assertEquals(ABoxThemeDefaults.darkColors, dark.colorTokens)
|
||||
assertEquals(
|
||||
ABoxAccentPalette.resolve(
|
||||
ABoxThemeDefaults.lightColors,
|
||||
UiPreferences().accentPreference,
|
||||
UiPreferences().colorStyle,
|
||||
UiPreferences().colorStandard,
|
||||
false,
|
||||
),
|
||||
light.colorTokens,
|
||||
)
|
||||
assertEquals(
|
||||
ABoxAccentPalette.resolve(
|
||||
ABoxThemeDefaults.darkColors,
|
||||
UiPreferences().accentPreference,
|
||||
UiPreferences().colorStyle,
|
||||
UiPreferences().colorStandard,
|
||||
true,
|
||||
),
|
||||
dark.colorTokens,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -42,7 +60,16 @@ class ABoxThemeResolverTest {
|
||||
dynamicColorTokens = dynamicTokens,
|
||||
)
|
||||
|
||||
assertEquals(ABoxThemeDefaults.lightColors, resolution.colorTokens)
|
||||
assertEquals(
|
||||
ABoxAccentPalette.resolve(
|
||||
ABoxThemeDefaults.lightColors,
|
||||
UiPreferences().accentPreference,
|
||||
UiPreferences().colorStyle,
|
||||
UiPreferences().colorStandard,
|
||||
false,
|
||||
),
|
||||
resolution.colorTokens,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -57,7 +84,16 @@ class ABoxThemeResolverTest {
|
||||
dynamicColorTokens = dynamicTokens,
|
||||
)
|
||||
|
||||
assertEquals(ABoxThemeDefaults.darkColors, resolution.colorTokens)
|
||||
assertEquals(
|
||||
ABoxAccentPalette.resolve(
|
||||
ABoxThemeDefaults.darkColors,
|
||||
UiPreferences().accentPreference,
|
||||
UiPreferences().colorStyle,
|
||||
UiPreferences().colorStandard,
|
||||
true,
|
||||
),
|
||||
resolution.colorTokens,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user