mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Move themes to separate files, save theme choice
This commit is contained in:
parent
106de18b3b
commit
d11025192e
@ -128,6 +128,8 @@ dependencies {
|
||||
|
||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
|
||||
implementation 'androidx.datastore:datastore-preferences:1.0.0'
|
||||
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||
|
||||
|
@ -48,6 +48,11 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LifecycleRegistry
|
||||
@ -55,6 +60,7 @@ import androidx.lifecycle.ViewModelStore
|
||||
import androidx.lifecycle.ViewModelStoreOwner
|
||||
import androidx.lifecycle.findViewTreeLifecycleOwner
|
||||
import androidx.lifecycle.findViewTreeViewModelStoreOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.setViewTreeLifecycleOwner
|
||||
import androidx.lifecycle.setViewTreeViewModelStoreOwner
|
||||
import androidx.savedstate.SavedStateRegistry
|
||||
@ -63,13 +69,26 @@ import androidx.savedstate.SavedStateRegistryOwner
|
||||
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
|
||||
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.futo.inputmethod.latin.common.Constants
|
||||
import org.futo.inputmethod.latin.uix.Action
|
||||
import org.futo.inputmethod.latin.uix.ActionBar
|
||||
import org.futo.inputmethod.latin.uix.KeyboardManagerForAction
|
||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOptions
|
||||
import org.futo.inputmethod.latin.uix.theme.Typography
|
||||
import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.DynamicSystemTheme
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.VoiceInputTheme
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
interface DynamicThemeProvider {
|
||||
@ -285,14 +304,36 @@ interface DynamicThemeProviderOwner {
|
||||
}
|
||||
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
val THEME_KEY = stringPreferencesKey("activeThemeOption")
|
||||
|
||||
suspend fun <T> Context.getSetting(key: Preferences.Key<T>, default: T): T {
|
||||
val valueFlow: Flow<T> =
|
||||
this.dataStore.data.map { preferences -> preferences[key] ?: default }.take(1)
|
||||
|
||||
return valueFlow.first()
|
||||
}
|
||||
|
||||
suspend fun <T> Context.setSetting(key: Preferences.Key<T>, value: T) {
|
||||
this.dataStore.edit { preferences ->
|
||||
preferences[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner, LatinIMELegacy.SuggestionStripController, DynamicThemeProviderOwner,
|
||||
KeyboardManagerForAction {
|
||||
private var activeColorScheme = DarkColorScheme
|
||||
private var colorSchemeLoaderJob: Job? = null
|
||||
|
||||
private var drawableProvider: DynamicThemeProvider? = null
|
||||
override fun getDrawableProvider(): DynamicThemeProvider {
|
||||
if(drawableProvider == null) {
|
||||
if(colorSchemeLoaderJob != null && !colorSchemeLoaderJob!!.isCompleted) {
|
||||
runBlocking {
|
||||
colorSchemeLoaderJob!!.join()
|
||||
}
|
||||
}
|
||||
drawableProvider = BasicThemeProvider(this, activeColorScheme)
|
||||
}
|
||||
|
||||
@ -310,7 +351,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
|
||||
// recreate the keyboard if not in action window, if we are in action window then
|
||||
// it'll be recreated when we exit
|
||||
if(currWindowAction != null) recreateKeyboard()
|
||||
if(currWindowAction == null) recreateKeyboard()
|
||||
|
||||
window.window?.navigationBarColor = drawableProvider!!.primaryKeyboardColor
|
||||
setContent()
|
||||
@ -344,12 +385,15 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
activeColorScheme = if(!DynamicColors.isDynamicColorAvailable()) {
|
||||
DarkColorScheme
|
||||
} else {
|
||||
val dCtx = DynamicColors.wrapContextIfAvailable(this)
|
||||
colorSchemeLoaderJob = lifecycleScope.launch {
|
||||
var themeKey = this@LatinIME.getSetting(THEME_KEY, DynamicSystemTheme.key)
|
||||
var themeOption = ThemeOptions[themeKey]
|
||||
if(themeOption == null || !themeOption.available(this@LatinIME)) {
|
||||
themeKey = VoiceInputTheme.key
|
||||
themeOption = ThemeOptions[themeKey]!!
|
||||
}
|
||||
|
||||
dynamicLightColorScheme(dCtx)
|
||||
activeColorScheme = themeOption.obtainColors(this@LatinIME)
|
||||
}
|
||||
|
||||
mSavedStateRegistryController.performRestore(null)
|
||||
@ -566,6 +610,8 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
override fun onWindowShown() {
|
||||
super.onWindowShown()
|
||||
latinIMELegacy.onWindowShown()
|
||||
|
||||
// TODO: Check here if the dynamic color scheme has changed, reset and rebuild if so
|
||||
}
|
||||
|
||||
override fun onWindowHidden() {
|
||||
@ -685,7 +731,14 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
);
|
||||
}
|
||||
|
||||
override fun updateTheme(newTheme: ColorScheme) {
|
||||
updateDrawableProvider(newTheme)
|
||||
override fun updateTheme(newTheme: ThemeOption) {
|
||||
assert(newTheme.available(this))
|
||||
updateDrawableProvider(newTheme.obtainColors(this))
|
||||
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
setSetting(THEME_KEY, newTheme.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,12 +3,13 @@ package org.futo.inputmethod.latin.uix
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
|
||||
|
||||
interface KeyboardManagerForAction {
|
||||
fun triggerSystemVoiceInput()
|
||||
|
||||
fun updateTheme(newTheme: ColorScheme)
|
||||
fun updateTheme(newTheme: ThemeOption)
|
||||
}
|
||||
|
||||
interface ActionWindow {
|
||||
|
@ -5,25 +5,33 @@ package org.futo.inputmethod.latin.uix
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.scrollable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
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.CompositionLocal
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOptionKeys
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOptions
|
||||
|
||||
|
||||
// TODO: For now, this calls CODE_SHORTCUT. In the future, we will want to
|
||||
@ -31,10 +39,27 @@ import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
val VoiceInputAction = Action(
|
||||
icon = R.drawable.mic_fill,
|
||||
name = "Voice Input",
|
||||
simplePressImpl = {
|
||||
it.triggerSystemVoiceInput()
|
||||
},
|
||||
windowImpl = null
|
||||
//simplePressImpl = {
|
||||
// it.triggerSystemVoiceInput()
|
||||
//},
|
||||
simplePressImpl = null,
|
||||
windowImpl = object : ActionWindow {
|
||||
@Composable
|
||||
override fun windowName(): String {
|
||||
return "Voice Input"
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun WindowContents(manager: KeyboardManagerForAction) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.mic_fill),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.align(Alignment.Center).size(48.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val ThemeAction = Action(
|
||||
@ -50,238 +75,21 @@ val ThemeAction = Action(
|
||||
@Composable
|
||||
override fun WindowContents(manager: KeyboardManagerForAction) {
|
||||
val context = LocalContext.current
|
||||
LazyColumn(modifier = Modifier.padding(8.dp, 0.dp).fillMaxWidth()) {
|
||||
item {
|
||||
Button(onClick = {
|
||||
manager.updateTheme(DarkColorScheme)
|
||||
}) {
|
||||
Text("Default voice input theme")
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
LazyColumn(modifier = Modifier
|
||||
.padding(8.dp, 0.dp)
|
||||
.fillMaxWidth())
|
||||
{
|
||||
items(ThemeOptionKeys.count()) {
|
||||
val key = ThemeOptionKeys[it]
|
||||
val themeOption = ThemeOptions[key]
|
||||
if(themeOption != null && themeOption.available(context)) {
|
||||
Button(onClick = {
|
||||
manager.updateTheme(dynamicLightColorScheme(context))
|
||||
manager.updateTheme(
|
||||
themeOption
|
||||
)
|
||||
}) {
|
||||
Text("Dynamic light color scheme")
|
||||
Text(themeOption.name)
|
||||
}
|
||||
|
||||
Button(onClick = {
|
||||
manager.updateTheme(dynamicDarkColorScheme(context))
|
||||
}) {
|
||||
Text("Dynamic dark color scheme")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Button(onClick = {
|
||||
val md_theme_light_primary = Color(0xFF6750A4)
|
||||
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_primaryContainer = Color(0xFFEADDFF)
|
||||
val md_theme_light_onPrimaryContainer = Color(0xFF21005D)
|
||||
val md_theme_light_secondary = Color(0xFF625B71)
|
||||
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_secondaryContainer = Color(0xFFE8DEF8)
|
||||
val md_theme_light_onSecondaryContainer = Color(0xFF1D192B)
|
||||
val md_theme_light_tertiary = Color(0xFF7D5260)
|
||||
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
|
||||
val md_theme_light_tertiaryContainer = Color(0xFFFFD8E4)
|
||||
val md_theme_light_onTertiaryContainer = Color(0xFF31111D)
|
||||
val md_theme_light_error = Color(0xFFB3261E)
|
||||
val md_theme_light_onError = Color(0xFFFFFFFF)
|
||||
val md_theme_light_errorContainer = Color(0xFFF9DEDC)
|
||||
val md_theme_light_onErrorContainer = Color(0xFF410E0B)
|
||||
val md_theme_light_outline = Color(0xFF79747E)
|
||||
val md_theme_light_background = Color(0xFFFFFBFE)
|
||||
val md_theme_light_onBackground = Color(0xFF1C1B1F)
|
||||
val md_theme_light_surface = Color(0xFFFFFBFE)
|
||||
val md_theme_light_onSurface = Color(0xFF1C1B1F)
|
||||
val md_theme_light_surfaceVariant = Color(0xFFE7E0EC)
|
||||
val md_theme_light_onSurfaceVariant = Color(0xFF49454F)
|
||||
val md_theme_light_inverseSurface = Color(0xFF313033)
|
||||
val md_theme_light_inverseOnSurface = Color(0xFFF4EFF4)
|
||||
val md_theme_light_inversePrimary = Color(0xFFD0BCFF)
|
||||
val md_theme_light_shadow = Color(0xFF000000)
|
||||
val md_theme_light_surfaceTint = Color(0xFF6750A4)
|
||||
val md_theme_light_outlineVariant = Color(0xFFCAC4D0)
|
||||
val md_theme_light_scrim = Color(0xFF000000)
|
||||
|
||||
manager.updateTheme(
|
||||
lightColorScheme(
|
||||
primary = md_theme_light_primary,
|
||||
onPrimary = md_theme_light_onPrimary,
|
||||
primaryContainer = md_theme_light_primaryContainer,
|
||||
onPrimaryContainer = md_theme_light_onPrimaryContainer,
|
||||
secondary = md_theme_light_secondary,
|
||||
onSecondary = md_theme_light_onSecondary,
|
||||
secondaryContainer = md_theme_light_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_light_onSecondaryContainer,
|
||||
tertiary = md_theme_light_tertiary,
|
||||
onTertiary = md_theme_light_onTertiary,
|
||||
tertiaryContainer = md_theme_light_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_light_onTertiaryContainer,
|
||||
error = md_theme_light_error,
|
||||
onError = md_theme_light_onError,
|
||||
errorContainer = md_theme_light_errorContainer,
|
||||
onErrorContainer = md_theme_light_onErrorContainer,
|
||||
outline = md_theme_light_outline,
|
||||
background = md_theme_light_background,
|
||||
onBackground = md_theme_light_onBackground,
|
||||
surface = md_theme_light_surface,
|
||||
onSurface = md_theme_light_onSurface,
|
||||
surfaceVariant = md_theme_light_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_light_onSurfaceVariant,
|
||||
inverseSurface = md_theme_light_inverseSurface,
|
||||
inverseOnSurface = md_theme_light_inverseOnSurface,
|
||||
inversePrimary = md_theme_light_inversePrimary,
|
||||
surfaceTint = md_theme_light_surfaceTint,
|
||||
outlineVariant = md_theme_light_outlineVariant,
|
||||
scrim = md_theme_light_scrim,
|
||||
)
|
||||
)
|
||||
}) {
|
||||
Text("Some random light theme")
|
||||
}
|
||||
|
||||
Button(onClick = {
|
||||
val md_theme_dark_primary = Color(0xFFD0BCFF)
|
||||
val md_theme_dark_onPrimary = Color(0xFF381E72)
|
||||
val md_theme_dark_primaryContainer = Color(0xFF4F378B)
|
||||
val md_theme_dark_onPrimaryContainer = Color(0xFFEADDFF)
|
||||
val md_theme_dark_secondary = Color(0xFFCCC2DC)
|
||||
val md_theme_dark_onSecondary = Color(0xFF332D41)
|
||||
val md_theme_dark_secondaryContainer = Color(0xFF4A4458)
|
||||
val md_theme_dark_onSecondaryContainer = Color(0xFFE8DEF8)
|
||||
val md_theme_dark_tertiary = Color(0xFFEFB8C8)
|
||||
val md_theme_dark_onTertiary = Color(0xFF492532)
|
||||
val md_theme_dark_tertiaryContainer = Color(0xFF633B48)
|
||||
val md_theme_dark_onTertiaryContainer = Color(0xFFFFD8E4)
|
||||
val md_theme_dark_error = Color(0xFFF2B8B5)
|
||||
val md_theme_dark_onError = Color(0xFF601410)
|
||||
val md_theme_dark_errorContainer = Color(0xFF8C1D18)
|
||||
val md_theme_dark_onErrorContainer = Color(0xFFF9DEDC)
|
||||
val md_theme_dark_outline = Color(0xFF938F99)
|
||||
val md_theme_dark_background = Color(0xFF1C1B1F)
|
||||
val md_theme_dark_onBackground = Color(0xFFE6E1E5)
|
||||
val md_theme_dark_surface = Color(0xFF1C1B1F)
|
||||
val md_theme_dark_onSurface = Color(0xFFE6E1E5)
|
||||
val md_theme_dark_surfaceVariant = Color(0xFF49454F)
|
||||
val md_theme_dark_onSurfaceVariant = Color(0xFFCAC4D0)
|
||||
val md_theme_dark_inverseSurface = Color(0xFFE6E1E5)
|
||||
val md_theme_dark_inverseOnSurface = Color(0xFF313033)
|
||||
val md_theme_dark_inversePrimary = Color(0xFF6750A4)
|
||||
val md_theme_dark_shadow = Color(0xFF000000)
|
||||
val md_theme_dark_surfaceTint = Color(0xFFD0BCFF)
|
||||
val md_theme_dark_outlineVariant = Color(0xFF49454F)
|
||||
val md_theme_dark_scrim = Color(0xFF000000)
|
||||
|
||||
manager.updateTheme(
|
||||
darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
primaryContainer = md_theme_dark_primaryContainer,
|
||||
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
|
||||
secondary = md_theme_dark_secondary,
|
||||
onSecondary = md_theme_dark_onSecondary,
|
||||
secondaryContainer = md_theme_dark_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
|
||||
tertiary = md_theme_dark_tertiary,
|
||||
onTertiary = md_theme_dark_onTertiary,
|
||||
tertiaryContainer = md_theme_dark_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
|
||||
error = md_theme_dark_error,
|
||||
onError = md_theme_dark_onError,
|
||||
errorContainer = md_theme_dark_errorContainer,
|
||||
onErrorContainer = md_theme_dark_onErrorContainer,
|
||||
outline = md_theme_dark_outline,
|
||||
background = md_theme_dark_background,
|
||||
onBackground = md_theme_dark_onBackground,
|
||||
surface = md_theme_dark_surface,
|
||||
onSurface = md_theme_dark_onSurface,
|
||||
surfaceVariant = md_theme_dark_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
|
||||
inverseSurface = md_theme_dark_inverseSurface,
|
||||
inverseOnSurface = md_theme_dark_inverseOnSurface,
|
||||
inversePrimary = md_theme_dark_inversePrimary,
|
||||
surfaceTint = md_theme_dark_surfaceTint,
|
||||
outlineVariant = md_theme_dark_outlineVariant,
|
||||
scrim = md_theme_dark_scrim,
|
||||
)
|
||||
)
|
||||
}) {
|
||||
Text("Some random dark theme")
|
||||
}
|
||||
|
||||
|
||||
Button(onClick = {
|
||||
val md_theme_dark_primary = Color(0xFFD0BCFF)
|
||||
val md_theme_dark_onPrimary = Color(0xFF381E72)
|
||||
val md_theme_dark_primaryContainer = Color(0xFF4F378B)
|
||||
val md_theme_dark_onPrimaryContainer = Color(0xFFEADDFF)
|
||||
val md_theme_dark_secondary = Color(0xFFCCC2DC)
|
||||
val md_theme_dark_onSecondary = Color(0xFF332D41)
|
||||
val md_theme_dark_secondaryContainer = Color(0xFF4A4458)
|
||||
val md_theme_dark_onSecondaryContainer = Color(0xFFE8DEF8)
|
||||
val md_theme_dark_tertiary = Color(0xFFEFB8C8)
|
||||
val md_theme_dark_onTertiary = Color(0xFF492532)
|
||||
val md_theme_dark_tertiaryContainer = Color(0xFF633B48)
|
||||
val md_theme_dark_onTertiaryContainer = Color(0xFFFFD8E4)
|
||||
val md_theme_dark_error = Color(0xFFF2B8B5)
|
||||
val md_theme_dark_onError = Color(0xFF601410)
|
||||
val md_theme_dark_errorContainer = Color(0xFF8C1D18)
|
||||
val md_theme_dark_onErrorContainer = Color(0xFFF9DEDC)
|
||||
val md_theme_dark_outline = Color(0xFF938F99)
|
||||
val md_theme_dark_background = Color(0xFF000000)
|
||||
val md_theme_dark_onBackground = Color(0xFFE6E1E5)
|
||||
val md_theme_dark_surface = Color(0xFF000000)
|
||||
val md_theme_dark_onSurface = Color(0xFFE6E1E5)
|
||||
val md_theme_dark_surfaceVariant = Color(0xFF49454F)
|
||||
val md_theme_dark_onSurfaceVariant = Color(0xFFCAC4D0)
|
||||
val md_theme_dark_inverseSurface = Color(0xFFE6E1E5)
|
||||
val md_theme_dark_inverseOnSurface = Color(0xFF313033)
|
||||
val md_theme_dark_inversePrimary = Color(0xFF6750A4)
|
||||
val md_theme_dark_shadow = Color(0xFF000000)
|
||||
val md_theme_dark_surfaceTint = Color(0xFFD0BCFF)
|
||||
val md_theme_dark_outlineVariant = Color(0xFF49454F)
|
||||
val md_theme_dark_scrim = Color(0xFF000000)
|
||||
|
||||
manager.updateTheme(
|
||||
darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
primaryContainer = md_theme_dark_primaryContainer,
|
||||
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
|
||||
secondary = md_theme_dark_secondary,
|
||||
onSecondary = md_theme_dark_onSecondary,
|
||||
secondaryContainer = md_theme_dark_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
|
||||
tertiary = md_theme_dark_tertiary,
|
||||
onTertiary = md_theme_dark_onTertiary,
|
||||
tertiaryContainer = md_theme_dark_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
|
||||
error = md_theme_dark_error,
|
||||
onError = md_theme_dark_onError,
|
||||
errorContainer = md_theme_dark_errorContainer,
|
||||
onErrorContainer = md_theme_dark_onErrorContainer,
|
||||
outline = md_theme_dark_outline,
|
||||
background = md_theme_dark_background,
|
||||
onBackground = md_theme_dark_onBackground,
|
||||
surface = md_theme_dark_surface,
|
||||
onSurface = md_theme_dark_onSurface,
|
||||
surfaceVariant = md_theme_dark_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
|
||||
inverseSurface = md_theme_dark_inverseSurface,
|
||||
inverseOnSurface = md_theme_dark_inverseOnSurface,
|
||||
inversePrimary = md_theme_dark_inversePrimary,
|
||||
surfaceTint = md_theme_dark_surfaceTint,
|
||||
outlineVariant = md_theme_dark_outlineVariant,
|
||||
scrim = md_theme_dark_scrim,
|
||||
)
|
||||
)
|
||||
}) {
|
||||
Text("AMOLED dark")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package org.futo.inputmethod.latin.uix.theme
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.AMOLEDDarkPurple
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.ClassicMaterialDark
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.DynamicDarkTheme
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.DynamicLightTheme
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.DynamicSystemTheme
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.VoiceInputTheme
|
||||
|
||||
data class ThemeOption(
|
||||
val key: String,
|
||||
val name: String, // TODO: @StringRes Int
|
||||
val available: (Context) -> Boolean,
|
||||
val obtainColors: (Context) -> ColorScheme,
|
||||
)
|
||||
|
||||
val ThemeOptions = hashMapOf(
|
||||
DynamicSystemTheme.key to DynamicSystemTheme,
|
||||
DynamicDarkTheme.key to DynamicDarkTheme,
|
||||
DynamicLightTheme.key to DynamicLightTheme,
|
||||
|
||||
ClassicMaterialDark.key to ClassicMaterialDark,
|
||||
VoiceInputTheme.key to VoiceInputTheme,
|
||||
AMOLEDDarkPurple.key to AMOLEDDarkPurple,
|
||||
)
|
||||
|
||||
val ThemeOptionKeys = arrayOf(
|
||||
DynamicSystemTheme.key,
|
||||
DynamicDarkTheme.key,
|
||||
DynamicLightTheme.key,
|
||||
|
||||
ClassicMaterialDark.key,
|
||||
VoiceInputTheme.key,
|
||||
AMOLEDDarkPurple.key,
|
||||
)
|
@ -0,0 +1,72 @@
|
||||
package org.futo.inputmethod.latin.uix.theme.presets
|
||||
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
|
||||
private val md_theme_dark_primary = Color(0xFFD0BCFF)
|
||||
private val md_theme_dark_onPrimary = Color(0xFF381E72)
|
||||
private val md_theme_dark_primaryContainer = Color(0xFF4F378B)
|
||||
private val md_theme_dark_onPrimaryContainer = Color(0xFFEADDFF)
|
||||
private val md_theme_dark_secondary = Color(0xFFCCC2DC)
|
||||
private val md_theme_dark_onSecondary = Color(0xFF332D41)
|
||||
private val md_theme_dark_secondaryContainer = Color(0xFF4A4458)
|
||||
private val md_theme_dark_onSecondaryContainer = Color(0xFFE8DEF8)
|
||||
private val md_theme_dark_tertiary = Color(0xFFEFB8C8)
|
||||
private val md_theme_dark_onTertiary = Color(0xFF492532)
|
||||
private val md_theme_dark_tertiaryContainer = Color(0xFF633B48)
|
||||
private val md_theme_dark_onTertiaryContainer = Color(0xFFFFD8E4)
|
||||
private val md_theme_dark_error = Color(0xFFF2B8B5)
|
||||
private val md_theme_dark_onError = Color(0xFF601410)
|
||||
private val md_theme_dark_errorContainer = Color(0xFF8C1D18)
|
||||
private val md_theme_dark_onErrorContainer = Color(0xFFF9DEDC)
|
||||
private val md_theme_dark_outline = Color(0xFF938F99)
|
||||
private val md_theme_dark_background = Color(0xFF000000)
|
||||
private val md_theme_dark_onBackground = Color(0xFFE6E1E5)
|
||||
private val md_theme_dark_surface = Color(0xFF000000)
|
||||
private val md_theme_dark_onSurface = Color(0xFFE6E1E5)
|
||||
private val md_theme_dark_surfaceVariant = Color(0xFF49454F)
|
||||
private val md_theme_dark_onSurfaceVariant = Color(0xFFCAC4D0)
|
||||
private val md_theme_dark_inverseSurface = Color(0xFFE6E1E5)
|
||||
private val md_theme_dark_inverseOnSurface = Color(0xFF313033)
|
||||
private val md_theme_dark_inversePrimary = Color(0xFF6750A4)
|
||||
private val md_theme_dark_shadow = Color(0xFF000000)
|
||||
private val md_theme_dark_surfaceTint = Color(0xFFD0BCFF)
|
||||
private val md_theme_dark_outlineVariant = Color(0xFF49454F)
|
||||
private val md_theme_dark_scrim = Color(0xFF000000)
|
||||
|
||||
private val colorScheme = darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
primaryContainer = md_theme_dark_primaryContainer,
|
||||
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
|
||||
secondary = md_theme_dark_secondary,
|
||||
onSecondary = md_theme_dark_onSecondary,
|
||||
secondaryContainer = md_theme_dark_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
|
||||
tertiary = md_theme_dark_tertiary,
|
||||
onTertiary = md_theme_dark_onTertiary,
|
||||
tertiaryContainer = md_theme_dark_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
|
||||
error = md_theme_dark_error,
|
||||
onError = md_theme_dark_onError,
|
||||
errorContainer = md_theme_dark_errorContainer,
|
||||
onErrorContainer = md_theme_dark_onErrorContainer,
|
||||
outline = md_theme_dark_outline,
|
||||
background = md_theme_dark_background,
|
||||
onBackground = md_theme_dark_onBackground,
|
||||
surface = md_theme_dark_surface,
|
||||
onSurface = md_theme_dark_onSurface,
|
||||
surfaceVariant = md_theme_dark_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
|
||||
inverseSurface = md_theme_dark_inverseSurface,
|
||||
inverseOnSurface = md_theme_dark_inverseOnSurface,
|
||||
inversePrimary = md_theme_dark_inversePrimary,
|
||||
surfaceTint = md_theme_dark_surfaceTint,
|
||||
outlineVariant = md_theme_dark_outlineVariant,
|
||||
scrim = md_theme_dark_scrim,
|
||||
)
|
||||
|
||||
val AMOLEDDarkPurple = ThemeOption("AMOLEDDarkPurple", "AMOLED Dark Purple", { true }) {
|
||||
colorScheme
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
package org.futo.inputmethod.latin.uix.theme.presets
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
|
||||
|
||||
private val md_theme_dark_primary = Color(0xFF80cbc4)
|
||||
private val md_theme_dark_onPrimary = Color(0xFFFFFFFF)
|
||||
private val md_theme_dark_primaryContainer = Color(0xFF00504B)
|
||||
private val md_theme_dark_onPrimaryContainer = Color(0xFF71F7ED)
|
||||
private val md_theme_dark_secondary = Color(0xFF80cbc4)
|
||||
private val md_theme_dark_onSecondary = Color(0xFFFFFFFF)
|
||||
private val md_theme_dark_secondaryContainer = Color(0xFF34434B)
|
||||
private val md_theme_dark_onSecondaryContainer = Color(0xFFFFFFFF)
|
||||
private val md_theme_dark_tertiary = Color(0xFF3582A2)
|
||||
private val md_theme_dark_onTertiary = Color(0xFFFFFFFF)
|
||||
private val md_theme_dark_tertiaryContainer = Color(0xFF004D64)
|
||||
private val md_theme_dark_onTertiaryContainer = Color(0xFFBDE9FF)
|
||||
private val md_theme_dark_error = Color(0xFFFFB4AB)
|
||||
private val md_theme_dark_errorContainer = Color(0xFF93000A)
|
||||
private val md_theme_dark_onError = Color(0xFF690005)
|
||||
private val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
|
||||
private val md_theme_dark_background = Color(0xFF21272b)
|
||||
private val md_theme_dark_onBackground = Color(0xFFFFFFFF)
|
||||
private val md_theme_dark_surface = Color(0xFF263238)
|
||||
private val md_theme_dark_onSurface = Color(0xFFFFFFFF)
|
||||
private val md_theme_dark_surfaceVariant = Color(0xFF3F4947)
|
||||
private val md_theme_dark_onSurfaceVariant = Color(0xFFBEC9C7)
|
||||
private val md_theme_dark_outline = Color(0xFF899391)
|
||||
private val md_theme_dark_inverseOnSurface = Color(0xFF001F2A)
|
||||
private val md_theme_dark_inverseSurface = Color(0xFFBFE9FF)
|
||||
private val md_theme_dark_inversePrimary = Color(0xFF006A64)
|
||||
private val md_theme_dark_shadow = Color(0xFF000000)
|
||||
private val md_theme_dark_surfaceTint = Color(0xFF4FDBD1)
|
||||
private val md_theme_dark_outlineVariant = Color(0xFF3F4947)
|
||||
private val md_theme_dark_scrim = Color(0xFF000000)
|
||||
|
||||
private val colorScheme = darkColorScheme(
|
||||
primary = md_theme_dark_primary,
|
||||
onPrimary = md_theme_dark_onPrimary,
|
||||
primaryContainer = md_theme_dark_primaryContainer,
|
||||
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
|
||||
secondary = md_theme_dark_secondary,
|
||||
onSecondary = md_theme_dark_onSecondary,
|
||||
secondaryContainer = md_theme_dark_secondaryContainer,
|
||||
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
|
||||
tertiary = md_theme_dark_tertiary,
|
||||
onTertiary = md_theme_dark_onTertiary,
|
||||
tertiaryContainer = md_theme_dark_tertiaryContainer,
|
||||
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
|
||||
error = md_theme_dark_error,
|
||||
onError = md_theme_dark_onError,
|
||||
errorContainer = md_theme_dark_errorContainer,
|
||||
onErrorContainer = md_theme_dark_onErrorContainer,
|
||||
outline = md_theme_dark_outline,
|
||||
background = md_theme_dark_background,
|
||||
onBackground = md_theme_dark_onBackground,
|
||||
surface = md_theme_dark_surface,
|
||||
onSurface = md_theme_dark_onSurface,
|
||||
surfaceVariant = md_theme_dark_surfaceVariant,
|
||||
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
|
||||
inverseSurface = md_theme_dark_inverseSurface,
|
||||
inverseOnSurface = md_theme_dark_inverseOnSurface,
|
||||
inversePrimary = md_theme_dark_inversePrimary,
|
||||
surfaceTint = md_theme_dark_surfaceTint,
|
||||
outlineVariant = md_theme_dark_outlineVariant,
|
||||
scrim = md_theme_dark_scrim,
|
||||
)
|
||||
|
||||
val ClassicMaterialDark = ThemeOption("ClassicMaterialDark", "AOSP Material Dark", { true }) {
|
||||
colorScheme
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun PreviewTheme() {
|
||||
MaterialTheme(colorScheme) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
Spacer(modifier = Modifier.weight(1.5f))
|
||||
Surface(color = MaterialTheme.colorScheme.background, modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)) {
|
||||
|
||||
}
|
||||
Surface(color = MaterialTheme.colorScheme.surface, modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1.0f)) {
|
||||
Box(modifier = Modifier.padding(16.dp)) {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.primary, modifier = Modifier
|
||||
.align(
|
||||
Alignment.BottomEnd
|
||||
)
|
||||
.height(32.dp)
|
||||
.width(48.dp),
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.futo.inputmethod.latin.uix.theme.presets
|
||||
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
|
||||
val DynamicSystemTheme = ThemeOption("DynamicSystem", "Dynamic System", { Build.VERSION.SDK_INT >= Build.VERSION_CODES.S }) {
|
||||
val uiModeManager = it.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
|
||||
when (uiModeManager.nightMode) {
|
||||
UiModeManager.MODE_NIGHT_YES -> dynamicDarkColorScheme(it)
|
||||
UiModeManager.MODE_NIGHT_NO -> dynamicLightColorScheme(it)
|
||||
UiModeManager.MODE_NIGHT_AUTO -> {
|
||||
val currentNightMode = it.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
if(currentNightMode == Configuration.UI_MODE_NIGHT_NO) {
|
||||
dynamicLightColorScheme(it)
|
||||
} else {
|
||||
dynamicDarkColorScheme(it)
|
||||
}
|
||||
}
|
||||
else -> dynamicDarkColorScheme(it)
|
||||
}
|
||||
}
|
||||
|
||||
val DynamicDarkTheme = ThemeOption("DynamicDark", "Dynamic Dark", { Build.VERSION.SDK_INT >= Build.VERSION_CODES.S }) {
|
||||
dynamicDarkColorScheme(it)
|
||||
}
|
||||
|
||||
val DynamicLightTheme = ThemeOption("DynamicLight", "Dynamic Light", { Build.VERSION.SDK_INT >= Build.VERSION_CODES.S }) {
|
||||
dynamicLightColorScheme(it)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package org.futo.inputmethod.latin.uix.theme.presets
|
||||
|
||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
|
||||
val VoiceInputTheme = ThemeOption("VoiceInputTheme", "Voice Input Theme", { true }) {
|
||||
DarkColorScheme
|
||||
}
|
Loading…
Reference in New Issue
Block a user