This commit is contained in:
coco
2026-07-03 16:23:31 +08:00
commit 7a4fb0e6ae
1979 changed files with 101570 additions and 0 deletions
@@ -0,0 +1,24 @@
package com.lowe.compose
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.lowe.compose.test", appContext.packageName)
}
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".ui.theme.ThemeActivity"
android:exported="false" />
</application>
</manifest>
@@ -0,0 +1,267 @@
@file:Suppress("UNUSED")
package com.lowe.compose
import androidx.compose.ui.graphics.Color
import com.lowe.resource.theme.ThemePrimaryKey
class MaterialThemeColor(private val key: ThemePrimaryKey, private val systemInDarkTheme: Boolean) {
fun getColorScheme() = ComposeThemeHelper.getThemeColorScheme(key)
.run { if (systemInDarkTheme) this.DarkColors else this.LightColors }
}
object DefaultColor {
val md_theme_light_primary = Color(0xFF9C4143)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFFFDAD9)
val md_theme_light_onPrimaryContainer = Color(0xFF410008)
val md_theme_light_secondary = Color(0xFF775656)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFFFDAD9)
val md_theme_light_onSecondaryContainer = Color(0xFF2C1515)
val md_theme_light_tertiary = Color(0xFF745A2F)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFFFDEAD)
val md_theme_light_onTertiaryContainer = Color(0xFF281900)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFFFBFF)
val md_theme_light_onBackground = Color(0xFF201A1A)
val md_theme_light_surface = Color(0xFFFFFBFF)
val md_theme_light_onSurface = Color(0xFF201A1A)
val md_theme_light_surfaceVariant = Color(0xFFF4DDDC)
val md_theme_light_onSurfaceVariant = Color(0xFF524343)
val md_theme_light_outline = Color(0xFF857372)
val md_theme_light_inverseOnSurface = Color(0xFFFBEEED)
val md_theme_light_inverseSurface = Color(0xFF362F2E)
val md_theme_light_inversePrimary = Color(0xFFFFB3B2)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF9C4143)
val md_theme_dark_primary = Color(0xFFFFB3B2)
val md_theme_dark_onPrimary = Color(0xFF5F1319)
val md_theme_dark_primaryContainer = Color(0xFF7E2A2E)
val md_theme_dark_onPrimaryContainer = Color(0xFFFFDAD9)
val md_theme_dark_secondary = Color(0xFFE6BDBB)
val md_theme_dark_onSecondary = Color(0xFF442929)
val md_theme_dark_secondaryContainer = Color(0xFF5D3F3F)
val md_theme_dark_onSecondaryContainer = Color(0xFFFFDAD9)
val md_theme_dark_tertiary = Color(0xFFE4C18D)
val md_theme_dark_onTertiary = Color(0xFF412D05)
val md_theme_dark_tertiaryContainer = Color(0xFF5A4319)
val md_theme_dark_onTertiaryContainer = Color(0xFFFFDEAD)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF201A1A)
val md_theme_dark_onBackground = Color(0xFFEDE0DF)
val md_theme_dark_surface = Color(0xFF201A1A)
val md_theme_dark_onSurface = Color(0xFFEDE0DF)
val md_theme_dark_surfaceVariant = Color(0xFF524343)
val md_theme_dark_onSurfaceVariant = Color(0xFFD7C1C0)
val md_theme_dark_outline = Color(0xFFA08C8B)
val md_theme_dark_inverseOnSurface = Color(0xFF201A1A)
val md_theme_dark_inverseSurface = Color(0xFFEDE0DF)
val md_theme_dark_inversePrimary = Color(0xFF9C4143)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFFFFB3B2)
val md_theme_seed = Color(0xFFB38988)
}
object BegoniaColor {
val begonia_red_light_primary = Color(0xFFBE0333)
val begonia_red_light_onPrimary = Color(0xFFFFFFFF)
val begonia_red_light_primaryContainer = Color(0xFFFFDADA)
val begonia_red_light_onPrimaryContainer = Color(0xFF40000B)
val begonia_red_light_secondary = Color(0xFF765657)
val begonia_red_light_onSecondary = Color(0xFFFFFFFF)
val begonia_red_light_secondaryContainer = Color(0xFFFFDADA)
val begonia_red_light_onSecondaryContainer = Color(0xFF2C1516)
val begonia_red_light_tertiary = Color(0xFF755A2F)
val begonia_red_light_onTertiary = Color(0xFFFFFFFF)
val begonia_red_light_tertiaryContainer = Color(0xFFFFDDB0)
val begonia_red_light_onTertiaryContainer = Color(0xFF291800)
val begonia_red_light_error = Color(0xFFBA1A1A)
val begonia_red_light_errorContainer = Color(0xFFFFDAD6)
val begonia_red_light_onError = Color(0xFFFFFFFF)
val begonia_red_light_onErrorContainer = Color(0xFF410002)
val begonia_red_light_background = Color(0xFFFFFBFF)
val begonia_red_light_onBackground = Color(0xFF201A1A)
val begonia_red_light_surface = Color(0xFFFFFBFF)
val begonia_red_light_onSurface = Color(0xFF201A1A)
val begonia_red_light_surfaceVariant = Color(0xFFF4DDDD)
val begonia_red_light_onSurfaceVariant = Color(0xFF524343)
val begonia_red_light_outline = Color(0xFF857373)
val begonia_red_light_inverseOnSurface = Color(0xFFFBEEED)
val begonia_red_light_inverseSurface = Color(0xFF362F2F)
val begonia_red_light_inversePrimary = Color(0xFFFFB3B4)
val begonia_red_light_shadow = Color(0xFF000000)
val begonia_red_light_surfaceTint = Color(0xFFBE0333)
val begonia_red_dark_primary = Color(0xFFFFB3B4)
val begonia_red_dark_onPrimary = Color(0xFF680017)
val begonia_red_dark_primaryContainer = Color(0xFF920025)
val begonia_red_dark_onPrimaryContainer = Color(0xFFFFDADA)
val begonia_red_dark_secondary = Color(0xFFE6BDBD)
val begonia_red_dark_onSecondary = Color(0xFF44292A)
val begonia_red_dark_secondaryContainer = Color(0xFF5D3F40)
val begonia_red_dark_onSecondaryContainer = Color(0xFFFFDADA)
val begonia_red_dark_tertiary = Color(0xFFE6C18D)
val begonia_red_dark_onTertiary = Color(0xFF422C05)
val begonia_red_dark_tertiaryContainer = Color(0xFF5B421A)
val begonia_red_dark_onTertiaryContainer = Color(0xFFFFDDB0)
val begonia_red_dark_error = Color(0xFFFFB4AB)
val begonia_red_dark_errorContainer = Color(0xFF93000A)
val begonia_red_dark_onError = Color(0xFF690005)
val begonia_red_dark_onErrorContainer = Color(0xFFFFDAD6)
val begonia_red_dark_background = Color(0xFF201A1A)
val begonia_red_dark_onBackground = Color(0xFFECE0DF)
val begonia_red_dark_surface = Color(0xFF201A1A)
val begonia_red_dark_onSurface = Color(0xFFECE0DF)
val begonia_red_dark_surfaceVariant = Color(0xFF524343)
val begonia_red_dark_onSurfaceVariant = Color(0xFFD7C1C1)
val begonia_red_dark_outline = Color(0xFF9F8C8C)
val begonia_red_dark_inverseOnSurface = Color(0xFF201A1A)
val begonia_red_dark_inverseSurface = Color(0xFFECE0DF)
val begonia_red_dark_inversePrimary = Color(0xFFBE0333)
val begonia_red_dark_shadow = Color(0xFF000000)
val begonia_red_dark_surfaceTint = Color(0xFFFFB3B4)
val begonia_red_seed = Color(0xFFF03752)
}
object IrisColor {
val iris_blue_light_primary = Color(0xFF006689)
val iris_blue_light_onPrimary = Color(0xFFFFFFFF)
val iris_blue_light_primaryContainer = Color(0xFFC3E8FF)
val iris_blue_light_onPrimaryContainer = Color(0xFF001E2C)
val iris_blue_light_secondary = Color(0xFF4E616D)
val iris_blue_light_onSecondary = Color(0xFFFFFFFF)
val iris_blue_light_secondaryContainer = Color(0xFFD1E5F3)
val iris_blue_light_onSecondaryContainer = Color(0xFF091E28)
val iris_blue_light_tertiary = Color(0xFF605A7D)
val iris_blue_light_onTertiary = Color(0xFFFFFFFF)
val iris_blue_light_tertiaryContainer = Color(0xFFE6DEFF)
val iris_blue_light_onTertiaryContainer = Color(0xFF1C1736)
val iris_blue_light_error = Color(0xFFBA1A1A)
val iris_blue_light_errorContainer = Color(0xFFFFDAD6)
val iris_blue_light_onError = Color(0xFFFFFFFF)
val iris_blue_light_onErrorContainer = Color(0xFF410002)
val iris_blue_light_background = Color(0xFFFBFCFE)
val iris_blue_light_onBackground = Color(0xFF191C1E)
val iris_blue_light_surface = Color(0xFFFBFCFE)
val iris_blue_light_onSurface = Color(0xFF191C1E)
val iris_blue_light_surfaceVariant = Color(0xFFDCE3E9)
val iris_blue_light_onSurfaceVariant = Color(0xFF41484D)
val iris_blue_light_outline = Color(0xFF71787D)
val iris_blue_light_inverseOnSurface = Color(0xFFF0F1F3)
val iris_blue_light_inverseSurface = Color(0xFF2E3133)
val iris_blue_light_inversePrimary = Color(0xFF78D1FF)
val iris_blue_light_shadow = Color(0xFF000000)
val iris_blue_light_surfaceTint = Color(0xFF006689)
val iris_blue_dark_primary = Color(0xFF78D1FF)
val iris_blue_dark_onPrimary = Color(0xFF003549)
val iris_blue_dark_primaryContainer = Color(0xFF004C68)
val iris_blue_dark_onPrimaryContainer = Color(0xFFC3E8FF)
val iris_blue_dark_secondary = Color(0xFFB5C9D7)
val iris_blue_dark_onSecondary = Color(0xFF20333D)
val iris_blue_dark_secondaryContainer = Color(0xFF364954)
val iris_blue_dark_onSecondaryContainer = Color(0xFFD1E5F3)
val iris_blue_dark_tertiary = Color(0xFFC9C1EA)
val iris_blue_dark_onTertiary = Color(0xFF312C4C)
val iris_blue_dark_tertiaryContainer = Color(0xFF484264)
val iris_blue_dark_onTertiaryContainer = Color(0xFFE6DEFF)
val iris_blue_dark_error = Color(0xFFFFB4AB)
val iris_blue_dark_errorContainer = Color(0xFF93000A)
val iris_blue_dark_onError = Color(0xFF690005)
val iris_blue_dark_onErrorContainer = Color(0xFFFFDAD6)
val iris_blue_dark_background = Color(0xFF191C1E)
val iris_blue_dark_onBackground = Color(0xFFE1E2E5)
val iris_blue_dark_surface = Color(0xFF191C1E)
val iris_blue_dark_onSurface = Color(0xFFE1E2E5)
val iris_blue_dark_surfaceVariant = Color(0xFF41484D)
val iris_blue_dark_onSurfaceVariant = Color(0xFFC0C7CD)
val iris_blue_dark_outline = Color(0xFF8A9297)
val iris_blue_dark_inverseOnSurface = Color(0xFF191C1E)
val iris_blue_dark_inverseSurface = Color(0xFFE1E2E5)
val iris_blue_dark_inversePrimary = Color(0xFF006689)
val iris_blue_dark_shadow = Color(0xFF000000)
val iris_blue_dark_surfaceTint = Color(0xFF78D1FF)
val iris_blue_seed = Color(0xFF158BB8)
}
object CardamomTipColor {
val cardamom_tip_green_light_primary = Color(0xFF006D43)
val cardamom_tip_green_light_onPrimary = Color(0xFFFFFFFF)
val cardamom_tip_green_light_primaryContainer = Color(0xFF91F7BD)
val cardamom_tip_green_light_onPrimaryContainer = Color(0xFF002111)
val cardamom_tip_green_light_secondary = Color(0xFF4E6355)
val cardamom_tip_green_light_onSecondary = Color(0xFFFFFFFF)
val cardamom_tip_green_light_secondaryContainer = Color(0xFFD0E8D6)
val cardamom_tip_green_light_onSecondaryContainer = Color(0xFF0B1F14)
val cardamom_tip_green_light_tertiary = Color(0xFF3C6471)
val cardamom_tip_green_light_onTertiary = Color(0xFFFFFFFF)
val cardamom_tip_green_light_tertiaryContainer = Color(0xFFBFE9F9)
val cardamom_tip_green_light_onTertiaryContainer = Color(0xFF001F27)
val cardamom_tip_green_light_error = Color(0xFFBA1A1A)
val cardamom_tip_green_light_errorContainer = Color(0xFFFFDAD6)
val cardamom_tip_green_light_onError = Color(0xFFFFFFFF)
val cardamom_tip_green_light_onErrorContainer = Color(0xFF410002)
val cardamom_tip_green_light_background = Color(0xFFFBFDF8)
val cardamom_tip_green_light_onBackground = Color(0xFF191C1A)
val cardamom_tip_green_light_surface = Color(0xFFFBFDF8)
val cardamom_tip_green_light_onSurface = Color(0xFF191C1A)
val cardamom_tip_green_light_surfaceVariant = Color(0xFFDCE5DC)
val cardamom_tip_green_light_onSurfaceVariant = Color(0xFF404942)
val cardamom_tip_green_light_outline = Color(0xFF717972)
val cardamom_tip_green_light_inverseOnSurface = Color(0xFFF0F1ED)
val cardamom_tip_green_light_inverseSurface = Color(0xFF2E312E)
val cardamom_tip_green_light_inversePrimary = Color(0xFF75DAA2)
val cardamom_tip_green_light_shadow = Color(0xFF000000)
val cardamom_tip_green_light_surfaceTint = Color(0xFF006D43)
val cardamom_tip_green_dark_primary = Color(0xFF75DAA2)
val cardamom_tip_green_dark_onPrimary = Color(0xFF003921)
val cardamom_tip_green_dark_primaryContainer = Color(0xFF005232)
val cardamom_tip_green_dark_onPrimaryContainer = Color(0xFF91F7BD)
val cardamom_tip_green_dark_secondary = Color(0xFFB5CCBB)
val cardamom_tip_green_dark_onSecondary = Color(0xFF213528)
val cardamom_tip_green_dark_secondaryContainer = Color(0xFF374B3E)
val cardamom_tip_green_dark_onSecondaryContainer = Color(0xFFD0E8D6)
val cardamom_tip_green_dark_tertiary = Color(0xFFA3CDDC)
val cardamom_tip_green_dark_onTertiary = Color(0xFF043541)
val cardamom_tip_green_dark_tertiaryContainer = Color(0xFF224C59)
val cardamom_tip_green_dark_onTertiaryContainer = Color(0xFFBFE9F9)
val cardamom_tip_green_dark_error = Color(0xFFFFB4AB)
val cardamom_tip_green_dark_errorContainer = Color(0xFF93000A)
val cardamom_tip_green_dark_onError = Color(0xFF690005)
val cardamom_tip_green_dark_onErrorContainer = Color(0xFFFFDAD6)
val cardamom_tip_green_dark_background = Color(0xFF191C1A)
val cardamom_tip_green_dark_onBackground = Color(0xFFE1E3DF)
val cardamom_tip_green_dark_surface = Color(0xFF191C1A)
val cardamom_tip_green_dark_onSurface = Color(0xFFE1E3DF)
val cardamom_tip_green_dark_surfaceVariant = Color(0xFF404942)
val cardamom_tip_green_dark_onSurfaceVariant = Color(0xFFC0C9C0)
val cardamom_tip_green_dark_outline = Color(0xFF8A938B)
val cardamom_tip_green_dark_inverseOnSurface = Color(0xFF191C1A)
val cardamom_tip_green_dark_inverseSurface = Color(0xFFE1E3DF)
val cardamom_tip_green_dark_inversePrimary = Color(0xFF006D43)
val cardamom_tip_green_dark_shadow = Color(0xFF000000)
val cardamom_tip_green_dark_surfaceTint = Color(0xFF75DAA2)
val cardamom_tip_green_seed = Color(0xFF5DBE8A)
}
@@ -0,0 +1,36 @@
package com.lowe.compose
import android.content.Context
import androidx.annotation.ColorInt
import com.lowe.common.base.app.CommonApplicationProxy
import com.lowe.resource.theme.ThemeModel
import com.lowe.resource.theme.ThemePrimaryKey
object ComposeThemeHelper {
fun getThemeColorScheme(key: ThemePrimaryKey): ChangeableTheme = when (key) {
ThemePrimaryKey.DEFAULT -> DefaultTheme
ThemePrimaryKey.DYNAMIC -> DynamicTheme
ThemePrimaryKey.BEGONIA_RED -> BegoniaTheme
ThemePrimaryKey.IRIS_BLUE -> IrisTheme
ThemePrimaryKey.CARDAMOM_TIP_GREEN -> CardamomTipTheme
}
fun snapshotThemes(selectedKey: ThemePrimaryKey): List<ThemeModel> =
ThemePrimaryKey.values().map {
ThemeModel(
it.storageKey,
it.primaryColor(CommonApplicationProxy.application),
it == selectedKey
)
}
}
@ColorInt
fun ThemePrimaryKey.primaryColor(context: Context): Int = when (this) {
ThemePrimaryKey.DEFAULT -> context.getColor(com.lowe.resource.R.color.seed)
ThemePrimaryKey.BEGONIA_RED -> context.getColor(com.lowe.resource.R.color.begonia_red_seed)
ThemePrimaryKey.IRIS_BLUE -> context.getColor(com.lowe.resource.R.color.iris_blue_seed)
ThemePrimaryKey.CARDAMOM_TIP_GREEN -> context.getColor(com.lowe.resource.R.color.cardamom_tip_green_seed)
ThemePrimaryKey.DYNAMIC -> context.getColor(android.R.color.system_accent1_600)
}
@@ -0,0 +1,279 @@
package com.lowe.compose
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import com.lowe.common.base.app.CommonApplicationProxy
sealed interface ChangeableTheme {
val LightColors: ColorScheme
val DarkColors: ColorScheme
}
object DynamicTheme : ChangeableTheme {
override val LightColors = dynamicLightColorScheme(CommonApplicationProxy.application)
override val DarkColors = dynamicDarkColorScheme(CommonApplicationProxy.application)
}
object DefaultTheme : ChangeableTheme {
override val LightColors = lightColorScheme(
primary = DefaultColor.md_theme_light_primary,
onPrimary = DefaultColor.md_theme_light_onPrimary,
primaryContainer = DefaultColor.md_theme_light_primaryContainer,
onPrimaryContainer = DefaultColor.md_theme_light_onPrimaryContainer,
secondary = DefaultColor.md_theme_light_secondary,
onSecondary = DefaultColor.md_theme_light_onSecondary,
secondaryContainer = DefaultColor.md_theme_light_secondaryContainer,
onSecondaryContainer = DefaultColor.md_theme_light_onSecondaryContainer,
tertiary = DefaultColor.md_theme_light_tertiary,
onTertiary = DefaultColor.md_theme_light_onTertiary,
tertiaryContainer = DefaultColor.md_theme_light_tertiaryContainer,
onTertiaryContainer = DefaultColor.md_theme_light_onTertiaryContainer,
error = DefaultColor.md_theme_light_error,
errorContainer = DefaultColor.md_theme_light_errorContainer,
onError = DefaultColor.md_theme_light_onError,
onErrorContainer = DefaultColor.md_theme_light_onErrorContainer,
background = DefaultColor.md_theme_light_background,
onBackground = DefaultColor.md_theme_light_onBackground,
surface = DefaultColor.md_theme_light_surface,
onSurface = DefaultColor.md_theme_light_onSurface,
surfaceVariant = DefaultColor.md_theme_light_surfaceVariant,
onSurfaceVariant = DefaultColor.md_theme_light_onSurfaceVariant,
outline = DefaultColor.md_theme_light_outline,
inverseOnSurface = DefaultColor.md_theme_light_inverseOnSurface,
inverseSurface = DefaultColor.md_theme_light_inverseSurface,
inversePrimary = DefaultColor.md_theme_light_inversePrimary,
surfaceTint = DefaultColor.md_theme_light_surfaceTint,
)
override val DarkColors = darkColorScheme(
primary = DefaultColor.md_theme_dark_primary,
onPrimary = DefaultColor.md_theme_dark_onPrimary,
primaryContainer = DefaultColor.md_theme_dark_primaryContainer,
onPrimaryContainer = DefaultColor.md_theme_dark_onPrimaryContainer,
secondary = DefaultColor.md_theme_dark_secondary,
onSecondary = DefaultColor.md_theme_dark_onSecondary,
secondaryContainer = DefaultColor.md_theme_dark_secondaryContainer,
onSecondaryContainer = DefaultColor.md_theme_dark_onSecondaryContainer,
tertiary = DefaultColor.md_theme_dark_tertiary,
onTertiary = DefaultColor.md_theme_dark_onTertiary,
tertiaryContainer = DefaultColor.md_theme_dark_tertiaryContainer,
onTertiaryContainer = DefaultColor.md_theme_dark_onTertiaryContainer,
error = DefaultColor.md_theme_dark_error,
errorContainer = DefaultColor.md_theme_dark_errorContainer,
onError = DefaultColor.md_theme_dark_onError,
onErrorContainer = DefaultColor.md_theme_dark_onErrorContainer,
background = DefaultColor.md_theme_dark_background,
onBackground = DefaultColor.md_theme_dark_onBackground,
surface = DefaultColor.md_theme_dark_surface,
onSurface = DefaultColor.md_theme_dark_onSurface,
surfaceVariant = DefaultColor.md_theme_dark_surfaceVariant,
onSurfaceVariant = DefaultColor.md_theme_dark_onSurfaceVariant,
outline = DefaultColor.md_theme_dark_outline,
inverseOnSurface = DefaultColor.md_theme_dark_inverseOnSurface,
inverseSurface = DefaultColor.md_theme_dark_inverseSurface,
inversePrimary = DefaultColor.md_theme_dark_inversePrimary,
surfaceTint = DefaultColor.md_theme_dark_surfaceTint,
)
}
object BegoniaTheme : ChangeableTheme {
override val LightColors = lightColorScheme(
primary = BegoniaColor.begonia_red_light_primary,
onPrimary = BegoniaColor.begonia_red_light_onPrimary,
primaryContainer = BegoniaColor.begonia_red_light_primaryContainer,
onPrimaryContainer = BegoniaColor.begonia_red_light_onPrimaryContainer,
secondary = BegoniaColor.begonia_red_light_secondary,
onSecondary = BegoniaColor.begonia_red_light_onSecondary,
secondaryContainer = BegoniaColor.begonia_red_light_secondaryContainer,
onSecondaryContainer = BegoniaColor.begonia_red_light_onSecondaryContainer,
tertiary = BegoniaColor.begonia_red_light_tertiary,
onTertiary = BegoniaColor.begonia_red_light_onTertiary,
tertiaryContainer = BegoniaColor.begonia_red_light_tertiaryContainer,
onTertiaryContainer = BegoniaColor.begonia_red_light_onTertiaryContainer,
error = BegoniaColor.begonia_red_light_error,
errorContainer = BegoniaColor.begonia_red_light_errorContainer,
onError = BegoniaColor.begonia_red_light_onError,
onErrorContainer = BegoniaColor.begonia_red_light_onErrorContainer,
background = BegoniaColor.begonia_red_light_background,
onBackground = BegoniaColor.begonia_red_light_onBackground,
surface = BegoniaColor.begonia_red_light_surface,
onSurface = BegoniaColor.begonia_red_light_onSurface,
surfaceVariant = BegoniaColor.begonia_red_light_surfaceVariant,
onSurfaceVariant = BegoniaColor.begonia_red_light_onSurfaceVariant,
outline = BegoniaColor.begonia_red_light_outline,
inverseOnSurface = BegoniaColor.begonia_red_light_inverseOnSurface,
inverseSurface = BegoniaColor.begonia_red_light_inverseSurface,
inversePrimary = BegoniaColor.begonia_red_light_inversePrimary,
surfaceTint = BegoniaColor.begonia_red_light_surfaceTint,
)
override val DarkColors = darkColorScheme(
primary = BegoniaColor.begonia_red_dark_primary,
onPrimary = BegoniaColor.begonia_red_dark_onPrimary,
primaryContainer = BegoniaColor.begonia_red_dark_primaryContainer,
onPrimaryContainer = BegoniaColor.begonia_red_dark_onPrimaryContainer,
secondary = BegoniaColor.begonia_red_dark_secondary,
onSecondary = BegoniaColor.begonia_red_dark_onSecondary,
secondaryContainer = BegoniaColor.begonia_red_dark_secondaryContainer,
onSecondaryContainer = BegoniaColor.begonia_red_dark_onSecondaryContainer,
tertiary = BegoniaColor.begonia_red_dark_tertiary,
onTertiary = BegoniaColor.begonia_red_dark_onTertiary,
tertiaryContainer = BegoniaColor.begonia_red_dark_tertiaryContainer,
onTertiaryContainer = BegoniaColor.begonia_red_dark_onTertiaryContainer,
error = BegoniaColor.begonia_red_dark_error,
errorContainer = BegoniaColor.begonia_red_dark_errorContainer,
onError = BegoniaColor.begonia_red_dark_onError,
onErrorContainer = BegoniaColor.begonia_red_dark_onErrorContainer,
background = BegoniaColor.begonia_red_dark_background,
onBackground = BegoniaColor.begonia_red_dark_onBackground,
surface = BegoniaColor.begonia_red_dark_surface,
onSurface = BegoniaColor.begonia_red_dark_onSurface,
surfaceVariant = BegoniaColor.begonia_red_dark_surfaceVariant,
onSurfaceVariant = BegoniaColor.begonia_red_dark_onSurfaceVariant,
outline = BegoniaColor.begonia_red_dark_outline,
inverseOnSurface = BegoniaColor.begonia_red_dark_inverseOnSurface,
inverseSurface = BegoniaColor.begonia_red_dark_inverseSurface,
inversePrimary = BegoniaColor.begonia_red_dark_inversePrimary,
surfaceTint = BegoniaColor.begonia_red_dark_surfaceTint,
)
}
object IrisTheme : ChangeableTheme {
override val LightColors = lightColorScheme(
primary = IrisColor.iris_blue_light_primary,
onPrimary = IrisColor.iris_blue_light_onPrimary,
primaryContainer = IrisColor.iris_blue_light_primaryContainer,
onPrimaryContainer = IrisColor.iris_blue_light_onPrimaryContainer,
secondary = IrisColor.iris_blue_light_secondary,
onSecondary = IrisColor.iris_blue_light_onSecondary,
secondaryContainer = IrisColor.iris_blue_light_secondaryContainer,
onSecondaryContainer = IrisColor.iris_blue_light_onSecondaryContainer,
tertiary = IrisColor.iris_blue_light_tertiary,
onTertiary = IrisColor.iris_blue_light_onTertiary,
tertiaryContainer = IrisColor.iris_blue_light_tertiaryContainer,
onTertiaryContainer = IrisColor.iris_blue_light_onTertiaryContainer,
error = IrisColor.iris_blue_light_error,
errorContainer = IrisColor.iris_blue_light_errorContainer,
onError = IrisColor.iris_blue_light_onError,
onErrorContainer = IrisColor.iris_blue_light_onErrorContainer,
background = IrisColor.iris_blue_light_background,
onBackground = IrisColor.iris_blue_light_onBackground,
surface = IrisColor.iris_blue_light_surface,
onSurface = IrisColor.iris_blue_light_onSurface,
surfaceVariant = IrisColor.iris_blue_light_surfaceVariant,
onSurfaceVariant = IrisColor.iris_blue_light_onSurfaceVariant,
outline = IrisColor.iris_blue_light_outline,
inverseOnSurface = IrisColor.iris_blue_light_inverseOnSurface,
inverseSurface = IrisColor.iris_blue_light_inverseSurface,
inversePrimary = IrisColor.iris_blue_light_inversePrimary,
surfaceTint = IrisColor.iris_blue_light_surfaceTint,
)
override val DarkColors = darkColorScheme(
primary = IrisColor.iris_blue_dark_primary,
onPrimary = IrisColor.iris_blue_dark_onPrimary,
primaryContainer = IrisColor.iris_blue_dark_primaryContainer,
onPrimaryContainer = IrisColor.iris_blue_dark_onPrimaryContainer,
secondary = IrisColor.iris_blue_dark_secondary,
onSecondary = IrisColor.iris_blue_dark_onSecondary,
secondaryContainer = IrisColor.iris_blue_dark_secondaryContainer,
onSecondaryContainer = IrisColor.iris_blue_dark_onSecondaryContainer,
tertiary = IrisColor.iris_blue_dark_tertiary,
onTertiary = IrisColor.iris_blue_dark_onTertiary,
tertiaryContainer = IrisColor.iris_blue_dark_tertiaryContainer,
onTertiaryContainer = IrisColor.iris_blue_dark_onTertiaryContainer,
error = IrisColor.iris_blue_dark_error,
errorContainer = IrisColor.iris_blue_dark_errorContainer,
onError = IrisColor.iris_blue_dark_onError,
onErrorContainer = IrisColor.iris_blue_dark_onErrorContainer,
background = IrisColor.iris_blue_dark_background,
onBackground = IrisColor.iris_blue_dark_onBackground,
surface = IrisColor.iris_blue_dark_surface,
onSurface = IrisColor.iris_blue_dark_onSurface,
surfaceVariant = IrisColor.iris_blue_dark_surfaceVariant,
onSurfaceVariant = IrisColor.iris_blue_dark_onSurfaceVariant,
outline = IrisColor.iris_blue_dark_outline,
inverseOnSurface = IrisColor.iris_blue_dark_inverseOnSurface,
inverseSurface = IrisColor.iris_blue_dark_inverseSurface,
inversePrimary = IrisColor.iris_blue_dark_inversePrimary,
surfaceTint = IrisColor.iris_blue_dark_surfaceTint,
)
}
object CardamomTipTheme : ChangeableTheme {
override val LightColors = lightColorScheme(
primary = CardamomTipColor.cardamom_tip_green_light_primary,
onPrimary = CardamomTipColor.cardamom_tip_green_light_onPrimary,
primaryContainer = CardamomTipColor.cardamom_tip_green_light_primaryContainer,
onPrimaryContainer = CardamomTipColor.cardamom_tip_green_light_onPrimaryContainer,
secondary = CardamomTipColor.cardamom_tip_green_light_secondary,
onSecondary = CardamomTipColor.cardamom_tip_green_light_onSecondary,
secondaryContainer = CardamomTipColor.cardamom_tip_green_light_secondaryContainer,
onSecondaryContainer = CardamomTipColor.cardamom_tip_green_light_onSecondaryContainer,
tertiary = CardamomTipColor.cardamom_tip_green_light_tertiary,
onTertiary = CardamomTipColor.cardamom_tip_green_light_onTertiary,
tertiaryContainer = CardamomTipColor.cardamom_tip_green_light_tertiaryContainer,
onTertiaryContainer = CardamomTipColor.cardamom_tip_green_light_onTertiaryContainer,
error = CardamomTipColor.cardamom_tip_green_light_error,
errorContainer = CardamomTipColor.cardamom_tip_green_light_errorContainer,
onError = CardamomTipColor.cardamom_tip_green_light_onError,
onErrorContainer = CardamomTipColor.cardamom_tip_green_light_onErrorContainer,
background = CardamomTipColor.cardamom_tip_green_light_background,
onBackground = CardamomTipColor.cardamom_tip_green_light_onBackground,
surface = CardamomTipColor.cardamom_tip_green_light_surface,
onSurface = CardamomTipColor.cardamom_tip_green_light_onSurface,
surfaceVariant = CardamomTipColor.cardamom_tip_green_light_surfaceVariant,
onSurfaceVariant = CardamomTipColor.cardamom_tip_green_light_onSurfaceVariant,
outline = CardamomTipColor.cardamom_tip_green_light_outline,
inverseOnSurface = CardamomTipColor.cardamom_tip_green_light_inverseOnSurface,
inverseSurface = CardamomTipColor.cardamom_tip_green_light_inverseSurface,
inversePrimary = CardamomTipColor.cardamom_tip_green_light_inversePrimary,
surfaceTint = CardamomTipColor.cardamom_tip_green_light_surfaceTint,
)
override val DarkColors = darkColorScheme(
primary = CardamomTipColor.cardamom_tip_green_dark_primary,
onPrimary = CardamomTipColor.cardamom_tip_green_dark_onPrimary,
primaryContainer = CardamomTipColor.cardamom_tip_green_dark_primaryContainer,
onPrimaryContainer = CardamomTipColor.cardamom_tip_green_dark_onPrimaryContainer,
secondary = CardamomTipColor.cardamom_tip_green_dark_secondary,
onSecondary = CardamomTipColor.cardamom_tip_green_dark_onSecondary,
secondaryContainer = CardamomTipColor.cardamom_tip_green_dark_secondaryContainer,
onSecondaryContainer = CardamomTipColor.cardamom_tip_green_dark_onSecondaryContainer,
tertiary = CardamomTipColor.cardamom_tip_green_dark_tertiary,
onTertiary = CardamomTipColor.cardamom_tip_green_dark_onTertiary,
tertiaryContainer = CardamomTipColor.cardamom_tip_green_dark_tertiaryContainer,
onTertiaryContainer = CardamomTipColor.cardamom_tip_green_dark_onTertiaryContainer,
error = CardamomTipColor.cardamom_tip_green_dark_error,
errorContainer = CardamomTipColor.cardamom_tip_green_dark_errorContainer,
onError = CardamomTipColor.cardamom_tip_green_dark_onError,
onErrorContainer = CardamomTipColor.cardamom_tip_green_dark_onErrorContainer,
background = CardamomTipColor.cardamom_tip_green_dark_background,
onBackground = CardamomTipColor.cardamom_tip_green_dark_onBackground,
surface = CardamomTipColor.cardamom_tip_green_dark_surface,
onSurface = CardamomTipColor.cardamom_tip_green_dark_onSurface,
surfaceVariant = CardamomTipColor.cardamom_tip_green_dark_surfaceVariant,
onSurfaceVariant = CardamomTipColor.cardamom_tip_green_dark_onSurfaceVariant,
outline = CardamomTipColor.cardamom_tip_green_dark_outline,
inverseOnSurface = CardamomTipColor.cardamom_tip_green_dark_inverseOnSurface,
inverseSurface = CardamomTipColor.cardamom_tip_green_dark_inverseSurface,
inversePrimary = CardamomTipColor.cardamom_tip_green_dark_inversePrimary,
surfaceTint = CardamomTipColor.cardamom_tip_green_dark_surfaceTint,
)
}
@Composable
fun ComposeAppTheme(colorScheme: ColorScheme, content: @Composable () -> Unit) {
MaterialTheme(colorScheme = colorScheme, content = content)
}
@@ -0,0 +1,10 @@
package com.lowe.compose.base
import androidx.activity.ComponentActivity
import com.lowe.common.base.BaseViewModel
abstract class BaseComposeActivity<VM : BaseViewModel>: ComponentActivity() {
protected abstract val viewModel: VM
}
@@ -0,0 +1,163 @@
package com.lowe.compose.ui.theme
import android.graphics.Typeface
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.google.android.material.color.DynamicColors
import com.lowe.compose.ComposeAppTheme
import com.lowe.compose.MaterialThemeColor
import com.lowe.compose.R
import com.lowe.compose.base.BaseComposeActivity
import com.lowe.compose.utils.collectAsStateWithLifecycle
import com.lowe.resource.theme.ThemeModel
import com.lowe.resource.theme.ThemePrimaryKey
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@AndroidEntryPoint
class ThemeActivity : BaseComposeActivity<ThemeViewModel>() {
override val viewModel: ThemeViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val themeState by viewModel.themeState.collectAsStateWithLifecycle()
val scope = rememberCoroutineScope()
val snackBarHostState = remember { SnackbarHostState() }
ComposeAppTheme(
MaterialThemeColor(
themeState,
isSystemInDarkTheme()
).getColorScheme()
) {
ThemeScreen(snackBarHostState, scope)
}
}
}
private fun applyTheme(themeModel: ThemeModel) {
viewModel.applySelectedTheme(themeModel)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ThemeScreen(snackBarHostState: SnackbarHostState, coroutineScope: CoroutineScope) {
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
text = stringResource(R.string.theme_title),
color = MaterialTheme.colorScheme.primary,
fontFamily = FontFamily(Typeface.DEFAULT_BOLD)
)
},
navigationIcon = {
BackIcon(onClick = this::finish)
}
)
}, snackbarHost = {
SnackbarHost(snackBarHostState)
}) { paddingValues ->
ThemeGrid(paddingValues, snackBarHostState, coroutineScope)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ThemeGrid(
paddingValues: PaddingValues,
snackBarHostState: SnackbarHostState,
coroutineScope: CoroutineScope
) {
val context = LocalContext.current
val themeList by viewModel.themeStateFlow.collectAsStateWithLifecycle()
LazyVerticalGrid(
modifier = Modifier.padding(paddingValues).fillMaxSize(),
columns = GridCells.Fixed(2)
) {
items(themeList, key = { it.key }) { theme ->
Surface(
modifier = Modifier.fillMaxWidth()
.wrapContentHeight()
.aspectRatio(ratio = 2 / 1.6f)
.padding(8.dp),
shape = RoundedCornerShape(16.dp),
color = Color(theme.primaryColor),
shadowElevation = 4.dp,
onClick = {
if (theme.key == ThemePrimaryKey.DYNAMIC.storageKey && DynamicColors.isDynamicColorAvailable().not()) {
coroutineScope.launch {
snackBarHostState.showSnackbar(context.getString(R.string.dynamic_color_tips))
}
} else applyTheme(theme)
}
) {
Box(contentAlignment = Alignment.Center) {
Text(text = theme.key, fontSize = 16.sp, color = Color.White)
if (theme.isSelected) {
Icon(
painter = painterResource(com.lowe.resource.R.drawable.ic_palette_32dp),
contentDescription = "",
modifier = Modifier.padding(8.dp).size(24.dp)
.align(Alignment.BottomEnd),
tint = Color.White
)
}
}
}
}
}
}
}
@Composable
fun BackIcon(onClick: () -> Unit = {}) {
TopBarIcon(
painter = painterResource(id = com.lowe.resource.R.drawable.ic_arrow_back_24dp),
contentDescription = "",
onClick = onClick
)
}
@Composable
fun TopBarIcon(
painter: Painter,
modifier: Modifier = Modifier,
onClick: () -> Unit = {},
tint: Color = MaterialTheme.colorScheme.primary,
contentDescription: String?,
) {
IconButton(onClick = onClick) {
Icon(
modifier = modifier.size(24.dp),
painter = painter,
tint = tint,
contentDescription = contentDescription
)
}
}
@@ -0,0 +1,35 @@
package com.lowe.compose.ui.theme
import androidx.lifecycle.viewModelScope
import com.lowe.common.base.BaseViewModel
import com.lowe.common.theme.ThemeViewModelDelegate
import com.lowe.compose.ComposeThemeHelper
import com.lowe.resource.theme.ThemeModel
import com.lowe.resource.theme.ThemePrimaryKey
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ThemeViewModel @Inject constructor(private val themeViewModelDelegate: ThemeViewModelDelegate) :
BaseViewModel(), ThemeViewModelDelegate by themeViewModelDelegate {
val themeStateFlow = themeState.distinctUntilChanged { old, new -> old == new }.map {
ComposeThemeHelper.snapshotThemes(it)
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
fun applySelectedTheme(theme: ThemeModel) {
viewModelScope.launch {
ThemePrimaryKey.values().firstOrNull { it.storageKey == theme.key }?.takeIf {
it != currentTheme
}?.let {
themeViewModelDelegate.applyTheme(it)
}
}
}
}
@@ -0,0 +1,42 @@
package com.lowe.compose.utils
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@Composable
fun <T> StateFlow<T>.collectAsStateWithLifecycle(
lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED
): State<T> = collectAsStateWithLifecycle(
initialValue = remember { this.value },
lifecycle = lifecycle,
minActiveState = minActiveState
)
@Composable
fun <T> Flow<T>.collectAsStateWithLifecycle(
initialValue: T,
lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED
): State<T> {
val currentValue = remember(this) { initialValue }
return produceState(
initialValue = currentValue,
key1 = this,
key2 = lifecycle,
key3 = minActiveState
) {
lifecycle.repeatOnLifecycle(minActiveState) {
this@collectAsStateWithLifecycle.collect {
this@produceState.value = it
}
}
}
}
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="theme_title">主题切换</string>
<string name="dynamic_color_tips">仅Android 12及以上版本支持</string>
</resources>
@@ -0,0 +1,17 @@
package com.lowe.compose
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}