diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 288464a8..59f7643c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -208,6 +208,7 @@ dependencies { implementation(project(":lib:kotlin")) implementation(project(":lib:native")) implementation(project(":lib:snygg")) + implementation(project(":lib:theme")) testImplementation(libs.equalsverifier) testImplementation(libs.kotest.assertions.core) diff --git a/app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Theme.kt b/app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Theme.kt index d8f832db..e1e7d098 100644 --- a/app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Theme.kt +++ b/app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Theme.kt @@ -18,22 +18,20 @@ package dev.patrickgold.florisboard.app.apptheme import android.app.Activity import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.TopAppBarDefaults -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.SideEffect -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat import dev.patrickgold.florisboard.app.AppTheme import org.florisboard.lib.android.AndroidVersion +import org.florisboard.lib.theme.amoledDark +import org.florisboard.lib.theme.amoledFlorisColorScheme +import org.florisboard.lib.theme.darkFlorisColorScheme +import org.florisboard.lib.theme.lightFlorisColorScheme /*private val AmoledDarkColorPalette = darkColorScheme( primary = Green500, @@ -74,86 +72,7 @@ private val LightColorPalette = lightColorScheme( */ )*/ -private val lightScheme = lightColorScheme( - primary = primaryLight, - onPrimary = onPrimaryLight, - primaryContainer = primaryContainerLight, - onPrimaryContainer = onPrimaryContainerLight, - secondary = secondaryLight, - onSecondary = onSecondaryLight, - secondaryContainer = secondaryContainerLight, - onSecondaryContainer = onSecondaryContainerLight, - tertiary = tertiaryLight, - onTertiary = onTertiaryLight, - tertiaryContainer = tertiaryContainerLight, - onTertiaryContainer = onTertiaryContainerLight, - error = errorLight, - onError = onErrorLight, - errorContainer = errorContainerLight, - onErrorContainer = onErrorContainerLight, - background = backgroundLight, - onBackground = onBackgroundLight, - surface = surfaceLight, - onSurface = onSurfaceLight, - surfaceVariant = surfaceVariantLight, - onSurfaceVariant = onSurfaceVariantLight, - outline = outlineLight, - outlineVariant = outlineVariantLight, - scrim = scrimLight, - inverseSurface = inverseSurfaceLight, - inverseOnSurface = inverseOnSurfaceLight, - inversePrimary = inversePrimaryLight, - surfaceDim = surfaceDimLight, - surfaceBright = surfaceBrightLight, - surfaceContainerLowest = surfaceContainerLowestLight, - surfaceContainerLow = surfaceContainerLowLight, - surfaceContainer = surfaceContainerLight, - surfaceContainerHigh = surfaceContainerHighLight, - surfaceContainerHighest = surfaceContainerHighestLight, -) -private val darkScheme = darkColorScheme( - primary = primaryDark, - onPrimary = onPrimaryDark, - primaryContainer = primaryContainerDark, - onPrimaryContainer = onPrimaryContainerDark, - secondary = secondaryDark, - onSecondary = onSecondaryDark, - secondaryContainer = secondaryContainerDark, - onSecondaryContainer = onSecondaryContainerDark, - tertiary = tertiaryDark, - onTertiary = onTertiaryDark, - tertiaryContainer = tertiaryContainerDark, - onTertiaryContainer = onTertiaryContainerDark, - error = errorDark, - onError = onErrorDark, - errorContainer = errorContainerDark, - onErrorContainer = onErrorContainerDark, - background = backgroundDark, - onBackground = onBackgroundDark, - surface = surfaceDark, - onSurface = onSurfaceDark, - surfaceVariant = surfaceVariantDark, - onSurfaceVariant = onSurfaceVariantDark, - outline = outlineDark, - outlineVariant = outlineVariantDark, - scrim = scrimDark, - inverseSurface = inverseSurfaceDark, - inverseOnSurface = inverseOnSurfaceDark, - inversePrimary = inversePrimaryDark, - surfaceDim = surfaceDimDark, - surfaceBright = surfaceBrightDark, - surfaceContainerLowest = surfaceContainerLowestDark, - surfaceContainerLow = surfaceContainerLowDark, - surfaceContainer = surfaceContainerDark, - surfaceContainerHigh = surfaceContainerHighDark, - surfaceContainerHighest = surfaceContainerHighestDark, -) - -private val amoledScheme = darkScheme.copy( - background = amoledDark, - surface = amoledDark -) @Composable fun FlorisAppTheme( @@ -172,8 +91,8 @@ fun FlorisAppTheme( else -> { when { - isSystemInDarkTheme() -> darkScheme - else -> lightScheme + isSystemInDarkTheme() -> darkFlorisColorScheme + else -> lightFlorisColorScheme } } } @@ -190,20 +109,20 @@ fun FlorisAppTheme( else -> { when { - isSystemInDarkTheme() -> amoledScheme - else -> lightScheme + isSystemInDarkTheme() -> amoledFlorisColorScheme + else -> lightFlorisColorScheme } } } AppTheme.LIGHT -> when { isMaterialYouAware -> dynamicLightColorScheme(LocalContext.current) - else -> lightScheme + else -> lightFlorisColorScheme } AppTheme.DARK -> when { isMaterialYouAware -> dynamicDarkColorScheme(LocalContext.current) - else -> darkScheme + else -> darkFlorisColorScheme } AppTheme.AMOLED_DARK -> when { @@ -212,24 +131,24 @@ fun FlorisAppTheme( surface = amoledDark, ) - else -> amoledScheme + else -> amoledFlorisColorScheme } } } else { when (theme) { AppTheme.AUTO -> when { - isSystemInDarkTheme() -> darkScheme - else -> lightScheme + isSystemInDarkTheme() -> darkFlorisColorScheme + else -> lightFlorisColorScheme } AppTheme.AUTO_AMOLED -> when { - isSystemInDarkTheme() -> darkScheme - else -> lightScheme + isSystemInDarkTheme() -> darkFlorisColorScheme + else -> lightFlorisColorScheme } - AppTheme.LIGHT -> lightScheme - AppTheme.DARK -> darkScheme - AppTheme.AMOLED_DARK -> amoledScheme + AppTheme.LIGHT -> lightFlorisColorScheme + AppTheme.DARK -> darkFlorisColorScheme + AppTheme.AMOLED_DARK -> amoledFlorisColorScheme } } diff --git a/app/src/main/kotlin/dev/patrickgold/florisboard/ime/theme/FlorisImeTheme.kt b/app/src/main/kotlin/dev/patrickgold/florisboard/ime/theme/FlorisImeTheme.kt index 9082382a..28e0fd99 100644 --- a/app/src/main/kotlin/dev/patrickgold/florisboard/ime/theme/FlorisImeTheme.kt +++ b/app/src/main/kotlin/dev/patrickgold/florisboard/ime/theme/FlorisImeTheme.kt @@ -40,6 +40,8 @@ import org.florisboard.lib.snygg.Snygg import org.florisboard.lib.snygg.SnyggStylesheet import org.florisboard.lib.snygg.ui.ProvideSnyggUiDefaults import org.florisboard.lib.snygg.ui.SnyggUiDefaults +import org.florisboard.lib.theme.darkFlorisColorScheme +import org.florisboard.lib.theme.lightFlorisColorScheme private val LocalConfig = staticCompositionLocalOf { error("not init") } private val LocalStyle = staticCompositionLocalOf { error("not init") } @@ -119,13 +121,13 @@ fun FlorisImeTheme(content: @Composable () -> Unit) { if (AndroidVersion.ATLEAST_API31_S) { dynamicDarkColorScheme(context) } else { - MaterialDarkFallbackPalette + darkFlorisColorScheme } } else { if (AndroidVersion.ATLEAST_API31_S) { dynamicLightColorScheme(context) } else { - MaterialLightFallbackPalette + lightFlorisColorScheme } } MaterialTheme(materialColors) { diff --git a/lib/snygg/build.gradle.kts b/lib/snygg/build.gradle.kts index 10c5f80c..71058f4c 100644 --- a/lib/snygg/build.gradle.kts +++ b/lib/snygg/build.gradle.kts @@ -45,6 +45,7 @@ android { dependencies { implementation(project(":lib:android")) implementation(project(":lib:kotlin")) + implementation(project(":lib:theme")) implementation(libs.androidx.core.ktx) implementation(libs.androidx.compose.material3) diff --git a/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggMaterialYouValue.kt b/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggMaterialYouValue.kt index 7eae722c..424e8070 100644 --- a/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggMaterialYouValue.kt +++ b/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggMaterialYouValue.kt @@ -21,10 +21,13 @@ import androidx.compose.material3.ColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.ui.graphics.Color +import org.florisboard.lib.android.AndroidVersion import org.florisboard.lib.snygg.value.MaterialYouColor.ColorName import org.florisboard.lib.snygg.value.MaterialYouColor.ColorNameId import org.florisboard.lib.snygg.value.MaterialYouColor.darkColorName import org.florisboard.lib.snygg.value.MaterialYouColor.lightColorName +import org.florisboard.lib.theme.darkFlorisColorScheme +import org.florisboard.lib.theme.lightFlorisColorScheme sealed interface SnyggMaterialYouValue : SnyggValue { val colorName: String @@ -78,12 +81,20 @@ object MaterialYouColor { private fun getAndCacheColorScheme(context: Context, dark: Boolean): ColorScheme { return if (dark) { if (darkColorScheme == null) { - darkColorScheme = dynamicDarkColorScheme(context) + darkColorScheme = if (AndroidVersion.ATLEAST_API31_S) { + dynamicDarkColorScheme(context) + } else { + darkFlorisColorScheme + } } darkColorScheme!! } else { if (lightColorScheme == null) { - lightColorScheme = dynamicLightColorScheme(context) + lightColorScheme = if (AndroidVersion.ATLEAST_API31_S) { + dynamicLightColorScheme(context) + } else { + lightFlorisColorScheme + } } lightColorScheme!! } @@ -138,6 +149,8 @@ object MaterialYouColor { fun loadColor(context: Context, colorName: String, dark: Boolean): Color { val colorScheme = getAndCacheColorScheme(context, dark) + println(colorName) + return when (colorName) { ColorPalette.Primary.id -> colorScheme.primary ColorPalette.OnPrimary.id -> colorScheme.onPrimary @@ -176,6 +189,9 @@ object MaterialYouColor { ColorPalette.SurfaceContainerLow.id -> colorScheme.surfaceContainerLow ColorPalette.SurfaceContainerLowest.id -> colorScheme.surfaceContainerLowest else -> colorScheme.primary + }.let { + println(it) + it } } } diff --git a/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggValue.kt b/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggValue.kt index 79061a77..0ae6d4a1 100644 --- a/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggValue.kt +++ b/lib/snygg/src/main/kotlin/org/florisboard/lib/snygg/value/SnyggValue.kt @@ -16,8 +16,6 @@ package org.florisboard.lib.snygg.value -import org.florisboard.lib.android.AndroidVersion - /** * SnyggValue is the base interface for all possible property values a Snygg stylesheet can hold. In general, a Snygg * value can be one specific type of value (e.g. a color, a keyword describing a behavior, shape, etc.). @@ -109,8 +107,8 @@ object SnyggImplicitInheritValue : SnyggValue, SnyggValueEncoder { val SnyggVarValueEncoders = listOfNotNull( SnyggSolidColorValue, - if (AndroidVersion.ATLEAST_API31_S) SnyggMaterialYouLightColorValue else null, - if (AndroidVersion.ATLEAST_API31_S) SnyggMaterialYouDarkColorValue else null, + SnyggMaterialYouLightColorValue, + SnyggMaterialYouDarkColorValue, //SnyggImageRefValue, SnyggRectangleShapeValue, SnyggCircleShapeValue, diff --git a/lib/theme/.gitignore b/lib/theme/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/lib/theme/.gitignore @@ -0,0 +1 @@ +/build diff --git a/lib/theme/build.gradle.kts b/lib/theme/build.gradle.kts new file mode 100644 index 00000000..f6fe37c1 --- /dev/null +++ b/lib/theme/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + alias(libs.plugins.agp.library) + alias(libs.plugins.kotlin.android) +} + +val projectMinSdk: String by project +val projectCompileSdk: String by project + +android { + namespace = "org.florisboard.lib.theme" + compileSdk = projectCompileSdk.toInt() + + defaultConfig { + minSdk = projectMinSdk.toInt() + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.kotlinx.serialization.json) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.material3) +} diff --git a/lib/theme/consumer-rules.pro b/lib/theme/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/lib/theme/proguard-rules.pro b/lib/theme/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/lib/theme/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/lib/theme/src/androidTest/kotlin/org/florisboard/lib/theme/ExampleInstrumentedTest.kt b/lib/theme/src/androidTest/kotlin/org/florisboard/lib/theme/ExampleInstrumentedTest.kt new file mode 100644 index 00000000..322d6d16 --- /dev/null +++ b/lib/theme/src/androidTest/kotlin/org/florisboard/lib/theme/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package org.florisboard.lib.theme + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * 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("org.florisboard.lib.theme.test", appContext.packageName) + } +} diff --git a/lib/theme/src/main/AndroidManifest.xml b/lib/theme/src/main/AndroidManifest.xml new file mode 100644 index 00000000..2c27e528 --- /dev/null +++ b/lib/theme/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Color.kt b/lib/theme/src/main/kotlin/org/florisboard/lib/theme/Color.kt similarity index 55% rename from app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Color.kt rename to lib/theme/src/main/kotlin/org/florisboard/lib/theme/Color.kt index 62f7bfee..63511efa 100644 --- a/app/src/main/kotlin/dev/patrickgold/florisboard/app/apptheme/Color.kt +++ b/lib/theme/src/main/kotlin/org/florisboard/lib/theme/Color.kt @@ -14,8 +14,10 @@ * limitations under the License. */ -package dev.patrickgold.florisboard.app.apptheme +package org.florisboard.lib.theme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.ui.graphics.Color /* Legacy Colors @@ -100,3 +102,85 @@ val surfaceContainerHighDark = Color(0xFF262C24) val surfaceContainerHighestDark = Color(0xFF30362E) val amoledDark = Color(0xFF000000) + + +val lightFlorisColorScheme = lightColorScheme( + primary = primaryLight, + onPrimary = onPrimaryLight, + primaryContainer = primaryContainerLight, + onPrimaryContainer = onPrimaryContainerLight, + secondary = secondaryLight, + onSecondary = onSecondaryLight, + secondaryContainer = secondaryContainerLight, + onSecondaryContainer = onSecondaryContainerLight, + tertiary = tertiaryLight, + onTertiary = onTertiaryLight, + tertiaryContainer = tertiaryContainerLight, + onTertiaryContainer = onTertiaryContainerLight, + error = errorLight, + onError = onErrorLight, + errorContainer = errorContainerLight, + onErrorContainer = onErrorContainerLight, + background = backgroundLight, + onBackground = onBackgroundLight, + surface = surfaceLight, + onSurface = onSurfaceLight, + surfaceVariant = surfaceVariantLight, + onSurfaceVariant = onSurfaceVariantLight, + outline = outlineLight, + outlineVariant = outlineVariantLight, + scrim = scrimLight, + inverseSurface = inverseSurfaceLight, + inverseOnSurface = inverseOnSurfaceLight, + inversePrimary = inversePrimaryLight, + surfaceDim = surfaceDimLight, + surfaceBright = surfaceBrightLight, + surfaceContainerLowest = surfaceContainerLowestLight, + surfaceContainerLow = surfaceContainerLowLight, + surfaceContainer = surfaceContainerLight, + surfaceContainerHigh = surfaceContainerHighLight, + surfaceContainerHighest = surfaceContainerHighestLight, +) + +val darkFlorisColorScheme = darkColorScheme( + primary = primaryDark, + onPrimary = onPrimaryDark, + primaryContainer = primaryContainerDark, + onPrimaryContainer = onPrimaryContainerDark, + secondary = secondaryDark, + onSecondary = onSecondaryDark, + secondaryContainer = secondaryContainerDark, + onSecondaryContainer = onSecondaryContainerDark, + tertiary = tertiaryDark, + onTertiary = onTertiaryDark, + tertiaryContainer = tertiaryContainerDark, + onTertiaryContainer = onTertiaryContainerDark, + error = errorDark, + onError = onErrorDark, + errorContainer = errorContainerDark, + onErrorContainer = onErrorContainerDark, + background = backgroundDark, + onBackground = onBackgroundDark, + surface = surfaceDark, + onSurface = onSurfaceDark, + surfaceVariant = surfaceVariantDark, + onSurfaceVariant = onSurfaceVariantDark, + outline = outlineDark, + outlineVariant = outlineVariantDark, + scrim = scrimDark, + inverseSurface = inverseSurfaceDark, + inverseOnSurface = inverseOnSurfaceDark, + inversePrimary = inversePrimaryDark, + surfaceDim = surfaceDimDark, + surfaceBright = surfaceBrightDark, + surfaceContainerLowest = surfaceContainerLowestDark, + surfaceContainerLow = surfaceContainerLowDark, + surfaceContainer = surfaceContainerDark, + surfaceContainerHigh = surfaceContainerHighDark, + surfaceContainerHighest = surfaceContainerHighestDark, +) + +val amoledFlorisColorScheme = darkFlorisColorScheme.copy( + background = amoledDark, + surface = amoledDark +) diff --git a/lib/theme/src/test/kotlin/org/florisboard/lib/theme/ExampleUnitTest.kt b/lib/theme/src/test/kotlin/org/florisboard/lib/theme/ExampleUnitTest.kt new file mode 100644 index 00000000..2b9c5655 --- /dev/null +++ b/lib/theme/src/test/kotlin/org/florisboard/lib/theme/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package org.florisboard.lib.theme + +import org.junit.Assert.* +import org.junit.Test + +/** + * 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) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 6f150abb..91eb591c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,3 +39,4 @@ include(":lib:android") include(":lib:kotlin") include(":lib:native") include(":lib:snygg") +include(":lib:theme")