mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Move certain things into separate files
This commit is contained in:
parent
05fce3bd09
commit
9d4ea1f7c1
@ -35,8 +35,8 @@ import android.view.View;
|
||||
|
||||
import org.futo.inputmethod.keyboard.internal.KeyDrawParams;
|
||||
import org.futo.inputmethod.keyboard.internal.KeyVisualAttributes;
|
||||
import org.futo.inputmethod.latin.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.DynamicThemeProviderOwner;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
import org.futo.inputmethod.latin.common.Constants;
|
||||
import org.futo.inputmethod.latin.utils.TypefaceUtils;
|
||||
|
@ -50,7 +50,7 @@ import org.futo.inputmethod.keyboard.internal.MoreKeySpec;
|
||||
import org.futo.inputmethod.keyboard.internal.NonDistinctMultitouchHelper;
|
||||
import org.futo.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview;
|
||||
import org.futo.inputmethod.keyboard.internal.TimerHandler;
|
||||
import org.futo.inputmethod.latin.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
import org.futo.inputmethod.latin.RichInputMethodSubtype;
|
||||
import org.futo.inputmethod.latin.SuggestedWords;
|
||||
|
@ -26,7 +26,7 @@ import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import org.futo.inputmethod.latin.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
|
||||
public final class KeyPreviewDrawParams {
|
||||
|
@ -20,7 +20,7 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import org.futo.inputmethod.latin.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
import org.futo.inputmethod.latin.utils.ResourceUtils;
|
||||
|
||||
|
@ -33,8 +33,8 @@ import org.futo.inputmethod.keyboard.Key;
|
||||
import org.futo.inputmethod.keyboard.Keyboard;
|
||||
import org.futo.inputmethod.keyboard.KeyboardId;
|
||||
import org.futo.inputmethod.keyboard.KeyboardTheme;
|
||||
import org.futo.inputmethod.latin.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.DynamicThemeProviderOwner;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
import org.futo.inputmethod.latin.common.Constants;
|
||||
import org.futo.inputmethod.latin.common.StringUtils;
|
||||
|
@ -22,7 +22,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import org.futo.inputmethod.latin.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider;
|
||||
import org.futo.inputmethod.latin.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -1,58 +1,35 @@
|
||||
package org.futo.inputmethod.latin
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.StateListDrawable
|
||||
import android.graphics.drawable.shapes.RoundRectShape
|
||||
import android.inputmethodservice.InputMethodService
|
||||
import android.util.TypedValue
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.inputmethod.CompletionInfo
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.view.inputmethod.InputMethodSubtype
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
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
|
||||
@ -60,7 +37,6 @@ 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
|
||||
@ -68,20 +44,18 @@ import androidx.savedstate.SavedStateRegistryController
|
||||
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.BasicThemeProvider
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProvider
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner
|
||||
import org.futo.inputmethod.latin.uix.KeyboardManagerForAction
|
||||
import org.futo.inputmethod.latin.uix.THEME_KEY
|
||||
import org.futo.inputmethod.latin.uix.deferGetSetting
|
||||
import org.futo.inputmethod.latin.uix.deferSetSetting
|
||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOptions
|
||||
@ -89,278 +63,9 @@ 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 {
|
||||
val primaryKeyboardColor: Int
|
||||
|
||||
val keyboardBackground: Drawable
|
||||
val keyBackground: Drawable
|
||||
val spaceBarBackground: Drawable
|
||||
|
||||
val keyFeedback: Drawable
|
||||
|
||||
val moreKeysKeyboardBackground: Drawable
|
||||
val popupKey: Drawable
|
||||
|
||||
@ColorInt
|
||||
fun getColor(i: Int): Int?
|
||||
|
||||
fun getDrawable(i: Int): Drawable?
|
||||
|
||||
companion object {
|
||||
@ColorInt
|
||||
fun getColorOrDefault(i: Int, @ColorInt default: Int, keyAttr: TypedArray, provider: DynamicThemeProvider?): Int {
|
||||
return (provider?.getColor(i)) ?: keyAttr.getColor(i, default)
|
||||
}
|
||||
|
||||
fun getDrawableOrDefault(i: Int, keyAttr: TypedArray, provider: DynamicThemeProvider?): Drawable? {
|
||||
return (provider?.getDrawable(i)) ?: keyAttr.getDrawable(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Expand the number of drawables this provides so it covers the full theme, and
|
||||
// build some system to dynamically change these colors
|
||||
class BasicThemeProvider(val context: Context, val overrideColorScheme: ColorScheme? = null) : DynamicThemeProvider {
|
||||
override val primaryKeyboardColor: Int
|
||||
|
||||
override val keyboardBackground: Drawable
|
||||
override val keyBackground: Drawable
|
||||
override val spaceBarBackground: Drawable
|
||||
|
||||
override val keyFeedback: Drawable
|
||||
|
||||
override val moreKeysKeyboardBackground: Drawable
|
||||
override val popupKey: Drawable
|
||||
|
||||
private val colors: HashMap<Int, Int> = HashMap()
|
||||
override fun getColor(i: Int): Int? {
|
||||
return colors[i]
|
||||
}
|
||||
|
||||
|
||||
private val drawables: HashMap<Int, Drawable> = HashMap()
|
||||
override fun getDrawable(i: Int): Drawable? {
|
||||
return drawables[i]
|
||||
}
|
||||
|
||||
private fun dp(dp: Dp): Float {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.value,
|
||||
context.resources.displayMetrics
|
||||
);
|
||||
}
|
||||
|
||||
private fun coloredRectangle(@ColorInt color: Int): GradientDrawable {
|
||||
return GradientDrawable().apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
setColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun coloredRoundedRectangle(@ColorInt color: Int, radius: Float): GradientDrawable {
|
||||
return GradientDrawable().apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
cornerRadius = radius
|
||||
setColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun coloredOval(@ColorInt color: Int): GradientDrawable {
|
||||
return GradientDrawable().apply {
|
||||
shape = GradientDrawable.OVAL
|
||||
cornerRadius = Float.MAX_VALUE
|
||||
setColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StateListDrawable.addStateWithHighlightLayerOnPressed(@ColorInt highlight: Int, stateSet: IntArray, drawable: Drawable) {
|
||||
addState(intArrayOf(android.R.attr.state_pressed) + stateSet, LayerDrawable(arrayOf(
|
||||
drawable,
|
||||
coloredRoundedRectangle(highlight, dp(8.dp))
|
||||
)))
|
||||
addState(stateSet, drawable)
|
||||
}
|
||||
|
||||
init {
|
||||
val colorScheme = if(overrideColorScheme != null) {
|
||||
overrideColorScheme
|
||||
}else if(!DynamicColors.isDynamicColorAvailable()) {
|
||||
DarkColorScheme
|
||||
} else {
|
||||
val dCtx = DynamicColors.wrapContextIfAvailable(context)
|
||||
|
||||
dynamicLightColorScheme(dCtx)
|
||||
}
|
||||
|
||||
|
||||
val primary = colorScheme.primary.toArgb()
|
||||
val secondary = colorScheme.secondary.toArgb()
|
||||
val highlight = colorScheme.outline.copy(alpha = 0.33f).toArgb()
|
||||
|
||||
val background = colorScheme.surface.toArgb()
|
||||
val surface = colorScheme.background.toArgb()
|
||||
val outline = colorScheme.outline.toArgb()
|
||||
|
||||
val onSecondary = colorScheme.onSecondary.toArgb()
|
||||
val onBackground = colorScheme.onBackground.toArgb()
|
||||
val onBackgroundHalf = colorScheme.onBackground.copy(alpha = 0.5f).toArgb()
|
||||
|
||||
val transparent = Color.TRANSPARENT
|
||||
|
||||
colors[R.styleable.Keyboard_Key_keyTextColor] = onBackground
|
||||
colors[R.styleable.Keyboard_Key_keyTextInactivatedColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyTextShadowColor] = 0
|
||||
colors[R.styleable.Keyboard_Key_functionalTextColor] = onBackground
|
||||
colors[R.styleable.Keyboard_Key_keyHintLetterColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyHintLabelColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyShiftedLetterHintInactivatedColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyPreviewTextColor] = onSecondary
|
||||
colors[R.styleable.MainKeyboardView_languageOnSpacebarTextColor] = onBackgroundHalf
|
||||
|
||||
drawables[R.styleable.Keyboard_iconDeleteKey] = AppCompatResources.getDrawable(context, R.drawable.delete)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
drawables[R.styleable.Keyboard_iconLanguageSwitchKey] = AppCompatResources.getDrawable(context, R.drawable.globe)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
|
||||
drawables[R.styleable.Keyboard_iconShiftKey] = AppCompatResources.getDrawable(context, R.drawable.shift)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
|
||||
drawables[R.styleable.Keyboard_iconShiftKeyShifted] = AppCompatResources.getDrawable(context, R.drawable.shiftshifted)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
|
||||
primaryKeyboardColor = background
|
||||
|
||||
keyboardBackground = coloredRectangle(background)
|
||||
|
||||
keyBackground = StateListDrawable().apply {
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_active),
|
||||
coloredRoundedRectangle(primary, dp(8.dp)).apply {
|
||||
setSize(dp(64.dp).toInt(), dp(48.dp).toInt())
|
||||
}
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_checkable, android.R.attr.state_checked),
|
||||
coloredRoundedRectangle(colorScheme.secondaryContainer.toArgb(), dp(8.dp))
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_checkable),
|
||||
coloredRectangle(transparent)
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_empty),
|
||||
coloredRectangle(transparent)
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(),
|
||||
coloredRectangle(transparent)
|
||||
)
|
||||
}
|
||||
|
||||
spaceBarBackground = StateListDrawable().apply {
|
||||
addState(intArrayOf(android.R.attr.state_pressed),
|
||||
LayerDrawable(arrayOf(
|
||||
coloredRoundedRectangle(highlight, dp(32.dp)),
|
||||
coloredRoundedRectangle(highlight, dp(32.dp))
|
||||
))
|
||||
)
|
||||
addState(intArrayOf(),
|
||||
coloredRoundedRectangle(highlight, dp(32.dp))
|
||||
)
|
||||
}
|
||||
|
||||
keyFeedback = ShapeDrawable().apply {
|
||||
paint.color = secondary
|
||||
shape = RoundRectShape(floatArrayOf(
|
||||
dp(8.dp),dp(8.dp),dp(8.dp),dp(8.dp),
|
||||
dp(8.dp),dp(8.dp),dp(8.dp),dp(8.dp),
|
||||
), null, null)
|
||||
|
||||
intrinsicWidth = dp(48.dp).roundToInt()
|
||||
intrinsicHeight = dp(24.dp).roundToInt()
|
||||
|
||||
setPadding(0, 0, 0, dp(50.dp).roundToInt())
|
||||
}
|
||||
|
||||
moreKeysKeyboardBackground = coloredRoundedRectangle(surface, dp(8.dp))
|
||||
popupKey = StateListDrawable().apply {
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(),
|
||||
coloredRoundedRectangle(surface, dp(8.dp))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface DynamicThemeProviderOwner {
|
||||
fun getDrawableProvider(): DynamicThemeProvider
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return drawableProvider!!
|
||||
}
|
||||
|
||||
private fun recreateKeyboard() {
|
||||
legacyInputView = latinIMELegacy.onCreateInputView()
|
||||
latinIMELegacy.loadKeyboard()
|
||||
}
|
||||
|
||||
private fun updateDrawableProvider(colorScheme: ColorScheme) {
|
||||
activeColorScheme = colorScheme
|
||||
drawableProvider = BasicThemeProvider(this, overrideColorScheme = colorScheme)
|
||||
|
||||
// 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()
|
||||
|
||||
window.window?.navigationBarColor = drawableProvider!!.primaryKeyboardColor
|
||||
setContent()
|
||||
}
|
||||
|
||||
private val latinIMELegacy = LatinIMELegacy(
|
||||
this as InputMethodService,
|
||||
this as LatinIMELegacy.SuggestionStripController
|
||||
)
|
||||
class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner,
|
||||
LatinIMELegacy.SuggestionStripController, DynamicThemeProviderOwner, KeyboardManagerForAction {
|
||||
|
||||
private val mSavedStateRegistryController = SavedStateRegistryController.create(this)
|
||||
|
||||
@ -368,6 +73,8 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
get() = mSavedStateRegistryController.savedStateRegistry
|
||||
|
||||
private val mLifecycleRegistry = LifecycleRegistry(this)
|
||||
private fun handleLifecycleEvent(event: Lifecycle.Event) =
|
||||
mLifecycleRegistry.handleLifecycleEvent(event)
|
||||
|
||||
override val lifecycle
|
||||
get() = mLifecycleRegistry
|
||||
@ -376,32 +83,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
override val viewModelStore
|
||||
get() = store
|
||||
|
||||
private fun handleLifecycleEvent(event: Lifecycle.Event) =
|
||||
mLifecycleRegistry.handleLifecycleEvent(event)
|
||||
|
||||
private val inputMethodManager: InputMethodManager
|
||||
get() = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
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]!!
|
||||
}
|
||||
|
||||
activeColorScheme = themeOption.obtainColors(this@LatinIME)
|
||||
}
|
||||
|
||||
mSavedStateRegistryController.performRestore(null)
|
||||
handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
|
||||
latinIMELegacy.onCreate()
|
||||
}
|
||||
|
||||
private fun setOwners() {
|
||||
val decorView = window.window?.decorView
|
||||
if (decorView?.findViewTreeLifecycleOwner() == null) {
|
||||
@ -415,9 +96,74 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var composeView: ComposeView? = null
|
||||
|
||||
private val latinIMELegacy = LatinIMELegacy(
|
||||
this as InputMethodService,
|
||||
this as LatinIMELegacy.SuggestionStripController
|
||||
)
|
||||
|
||||
private var activeColorScheme = DarkColorScheme
|
||||
private var colorSchemeLoaderJob: Job? = null
|
||||
|
||||
private var drawableProvider: DynamicThemeProvider? = null
|
||||
|
||||
private var currWindowAction: Action? = null
|
||||
private fun isActionWindowOpen(): Boolean {
|
||||
return currWindowAction != null
|
||||
}
|
||||
|
||||
private fun recreateKeyboard() {
|
||||
legacyInputView = latinIMELegacy.onCreateInputView()
|
||||
latinIMELegacy.loadKeyboard()
|
||||
}
|
||||
|
||||
private fun updateDrawableProvider(colorScheme: ColorScheme) {
|
||||
activeColorScheme = colorScheme
|
||||
drawableProvider = BasicThemeProvider(this, overrideColorScheme = colorScheme)
|
||||
|
||||
// recreate the keyboard if not in action window, if we are in action window then
|
||||
// it'll be recreated when we exit
|
||||
if (!isActionWindowOpen()) recreateKeyboard()
|
||||
|
||||
window.window?.navigationBarColor = drawableProvider!!.primaryKeyboardColor
|
||||
setContent()
|
||||
}
|
||||
|
||||
override fun getDrawableProvider(): DynamicThemeProvider {
|
||||
if (drawableProvider == null) {
|
||||
if (colorSchemeLoaderJob != null && !colorSchemeLoaderJob!!.isCompleted) {
|
||||
// Must have completed by now!
|
||||
runBlocking {
|
||||
colorSchemeLoaderJob!!.join()
|
||||
}
|
||||
}
|
||||
drawableProvider = BasicThemeProvider(this, activeColorScheme)
|
||||
}
|
||||
|
||||
return drawableProvider!!
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
colorSchemeLoaderJob = deferGetSetting(THEME_KEY, DynamicSystemTheme.key) {
|
||||
var themeKey = it
|
||||
var themeOption = ThemeOptions[themeKey]
|
||||
if (themeOption == null || !themeOption.available(this@LatinIME)) {
|
||||
themeKey = VoiceInputTheme.key
|
||||
themeOption = ThemeOptions[themeKey]!!
|
||||
}
|
||||
|
||||
activeColorScheme = themeOption.obtainColors(this@LatinIME)
|
||||
}
|
||||
|
||||
mSavedStateRegistryController.performRestore(null)
|
||||
handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
|
||||
latinIMELegacy.onCreate()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
latinIMELegacy.onDestroy()
|
||||
super.onDestroy()
|
||||
@ -450,11 +196,10 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
return composeView!!
|
||||
}
|
||||
|
||||
private var currWindowAction: Action? = null
|
||||
private fun onActionActivated(action: Action) {
|
||||
if(action.windowImpl != null) {
|
||||
if (action.windowImpl != null) {
|
||||
enterActionWindowView(action)
|
||||
} else if(action.simplePressImpl != null) {
|
||||
} else if (action.simplePressImpl != null) {
|
||||
action.simplePressImpl.invoke(this)
|
||||
} else {
|
||||
throw IllegalStateException("An action must have either a window implementation or a simple press implementation")
|
||||
@ -512,9 +257,11 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
private fun ActionViewWithHeader(action: Action) {
|
||||
val windowImpl = action.windowImpl!!
|
||||
Column {
|
||||
Surface(modifier = Modifier
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(40.dp), color = MaterialTheme.colorScheme.background)
|
||||
.height(40.dp), color = MaterialTheme.colorScheme.background
|
||||
)
|
||||
{
|
||||
Row {
|
||||
IconButton(onClick = {
|
||||
@ -526,13 +273,18 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
)
|
||||
}
|
||||
|
||||
Text(windowImpl.windowName(), style = Typography.titleMedium, modifier = Modifier.align(CenterVertically))
|
||||
Text(
|
||||
windowImpl.windowName(),
|
||||
style = Typography.titleMedium,
|
||||
modifier = Modifier.align(CenterVertically)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(with(LocalDensity.current) { inputViewHeight.toDp() })) {
|
||||
.height(with(LocalDensity.current) { inputViewHeight.toDp() })
|
||||
) {
|
||||
windowImpl.WindowContents(manager = this@LatinIME)
|
||||
}
|
||||
}
|
||||
@ -561,7 +313,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
legacyInputView = newView
|
||||
setContent()
|
||||
|
||||
if(composeView != null) {
|
||||
if (composeView != null) {
|
||||
latinIMELegacy.setComposeInputView(composeView)
|
||||
}
|
||||
|
||||
@ -571,7 +323,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
override fun setInputView(view: View?) {
|
||||
super.setInputView(view)
|
||||
|
||||
if(composeView != null) {
|
||||
if (composeView != null) {
|
||||
latinIMELegacy.setComposeInputView(composeView)
|
||||
}
|
||||
|
||||
@ -627,9 +379,23 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
candidatesStart: Int,
|
||||
candidatesEnd: Int
|
||||
) {
|
||||
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd)
|
||||
super.onUpdateSelection(
|
||||
oldSelStart,
|
||||
oldSelEnd,
|
||||
newSelStart,
|
||||
newSelEnd,
|
||||
candidatesStart,
|
||||
candidatesEnd
|
||||
)
|
||||
|
||||
latinIMELegacy.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd)
|
||||
latinIMELegacy.onUpdateSelection(
|
||||
oldSelStart,
|
||||
oldSelEnd,
|
||||
newSelStart,
|
||||
newSelEnd,
|
||||
candidatesStart,
|
||||
candidatesEnd
|
||||
)
|
||||
}
|
||||
|
||||
override fun onExtractedTextClicked() {
|
||||
@ -653,7 +419,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
|
||||
override fun onComputeInsets(outInsets: Insets?) {
|
||||
// This method may be called before {@link #setInputView(View)}.
|
||||
if (legacyInputView == null) {
|
||||
if (legacyInputView == null || composeView == null) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -684,7 +450,10 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
|
||||
override fun onShowInputRequested(flags: Int, configChange: Boolean): Boolean {
|
||||
return latinIMELegacy.onShowInputRequested(flags, configChange) || super.onShowInputRequested(flags, configChange)
|
||||
return latinIMELegacy.onShowInputRequested(
|
||||
flags,
|
||||
configChange
|
||||
) || super.onShowInputRequested(flags, configChange)
|
||||
}
|
||||
|
||||
override fun onEvaluateInputViewShown(): Boolean {
|
||||
@ -735,10 +504,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
assert(newTheme.available(this))
|
||||
updateDrawableProvider(newTheme.obtainColors(this))
|
||||
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
setSetting(THEME_KEY, newTheme.key)
|
||||
}
|
||||
}
|
||||
deferSetSetting(THEME_KEY, newTheme.key)
|
||||
}
|
||||
}
|
@ -90,6 +90,7 @@ import org.futo.inputmethod.latin.settings.SettingsValues;
|
||||
import org.futo.inputmethod.latin.suggestions.SuggestionStripView;
|
||||
import org.futo.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
|
||||
import org.futo.inputmethod.latin.touchinputconsumer.GestureConsumer;
|
||||
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner;
|
||||
import org.futo.inputmethod.latin.utils.ApplicationUtils;
|
||||
import org.futo.inputmethod.latin.utils.DialogUtils;
|
||||
import org.futo.inputmethod.latin.utils.ImportantNoticeUtils;
|
||||
|
221
java/src/org/futo/inputmethod/latin/uix/BasicThemeProvider.kt
Normal file
221
java/src/org/futo/inputmethod/latin/uix/BasicThemeProvider.kt
Normal file
@ -0,0 +1,221 @@
|
||||
package org.futo.inputmethod.latin.uix
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.graphics.drawable.ShapeDrawable
|
||||
import android.graphics.drawable.StateListDrawable
|
||||
import android.graphics.drawable.shapes.RoundRectShape
|
||||
import android.util.TypedValue
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
// TODO: Expand the number of drawables this provides so it covers the full theme, and
|
||||
// build some system to dynamically change these colors
|
||||
class BasicThemeProvider(val context: Context, val overrideColorScheme: ColorScheme? = null) :
|
||||
DynamicThemeProvider {
|
||||
override val primaryKeyboardColor: Int
|
||||
|
||||
override val keyboardBackground: Drawable
|
||||
override val keyBackground: Drawable
|
||||
override val spaceBarBackground: Drawable
|
||||
|
||||
override val keyFeedback: Drawable
|
||||
|
||||
override val moreKeysKeyboardBackground: Drawable
|
||||
override val popupKey: Drawable
|
||||
|
||||
private val colors: HashMap<Int, Int> = HashMap()
|
||||
override fun getColor(i: Int): Int? {
|
||||
return colors[i]
|
||||
}
|
||||
|
||||
|
||||
private val drawables: HashMap<Int, Drawable> = HashMap()
|
||||
override fun getDrawable(i: Int): Drawable? {
|
||||
return drawables[i]
|
||||
}
|
||||
|
||||
private fun dp(dp: Dp): Float {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.value,
|
||||
context.resources.displayMetrics
|
||||
);
|
||||
}
|
||||
|
||||
private fun coloredRectangle(@ColorInt color: Int): GradientDrawable {
|
||||
return GradientDrawable().apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
setColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun coloredRoundedRectangle(@ColorInt color: Int, radius: Float): GradientDrawable {
|
||||
return GradientDrawable().apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
cornerRadius = radius
|
||||
setColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun coloredOval(@ColorInt color: Int): GradientDrawable {
|
||||
return GradientDrawable().apply {
|
||||
shape = GradientDrawable.OVAL
|
||||
cornerRadius = Float.MAX_VALUE
|
||||
setColor(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StateListDrawable.addStateWithHighlightLayerOnPressed(@ColorInt highlight: Int, stateSet: IntArray, drawable: Drawable) {
|
||||
addState(intArrayOf(android.R.attr.state_pressed) + stateSet, LayerDrawable(
|
||||
arrayOf(
|
||||
drawable,
|
||||
coloredRoundedRectangle(highlight, dp(8.dp))
|
||||
)
|
||||
)
|
||||
)
|
||||
addState(stateSet, drawable)
|
||||
}
|
||||
|
||||
init {
|
||||
val colorScheme = if(overrideColorScheme != null) {
|
||||
overrideColorScheme
|
||||
}else if(!DynamicColors.isDynamicColorAvailable()) {
|
||||
DarkColorScheme
|
||||
} else {
|
||||
val dCtx = DynamicColors.wrapContextIfAvailable(context)
|
||||
|
||||
dynamicLightColorScheme(dCtx)
|
||||
}
|
||||
|
||||
|
||||
val primary = colorScheme.primary.toArgb()
|
||||
val secondary = colorScheme.secondary.toArgb()
|
||||
val highlight = colorScheme.outline.copy(alpha = 0.33f).toArgb()
|
||||
|
||||
val background = colorScheme.surface.toArgb()
|
||||
val surface = colorScheme.background.toArgb()
|
||||
val outline = colorScheme.outline.toArgb()
|
||||
|
||||
val onSecondary = colorScheme.onSecondary.toArgb()
|
||||
val onBackground = colorScheme.onBackground.toArgb()
|
||||
val onBackgroundHalf = colorScheme.onBackground.copy(alpha = 0.5f).toArgb()
|
||||
|
||||
val transparent = Color.TRANSPARENT
|
||||
|
||||
colors[R.styleable.Keyboard_Key_keyTextColor] = onBackground
|
||||
colors[R.styleable.Keyboard_Key_keyTextInactivatedColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyTextShadowColor] = 0
|
||||
colors[R.styleable.Keyboard_Key_functionalTextColor] = onBackground
|
||||
colors[R.styleable.Keyboard_Key_keyHintLetterColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyHintLabelColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyShiftedLetterHintInactivatedColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor] = onBackgroundHalf
|
||||
colors[R.styleable.Keyboard_Key_keyPreviewTextColor] = onSecondary
|
||||
colors[R.styleable.MainKeyboardView_languageOnSpacebarTextColor] = onBackgroundHalf
|
||||
|
||||
drawables[R.styleable.Keyboard_iconDeleteKey] = AppCompatResources.getDrawable(
|
||||
context,
|
||||
R.drawable.delete
|
||||
)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
drawables[R.styleable.Keyboard_iconLanguageSwitchKey] = AppCompatResources.getDrawable(
|
||||
context,
|
||||
R.drawable.globe
|
||||
)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
|
||||
drawables[R.styleable.Keyboard_iconShiftKey] = AppCompatResources.getDrawable(
|
||||
context,
|
||||
R.drawable.shift
|
||||
)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
|
||||
drawables[R.styleable.Keyboard_iconShiftKeyShifted] = AppCompatResources.getDrawable(
|
||||
context,
|
||||
R.drawable.shiftshifted
|
||||
)!!.apply {
|
||||
setTint(onBackground)
|
||||
}
|
||||
|
||||
primaryKeyboardColor = background
|
||||
|
||||
keyboardBackground = coloredRectangle(background)
|
||||
|
||||
keyBackground = StateListDrawable().apply {
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_active),
|
||||
coloredRoundedRectangle(primary, dp(8.dp)).apply {
|
||||
setSize(dp(64.dp).toInt(), dp(48.dp).toInt())
|
||||
}
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_checkable, android.R.attr.state_checked),
|
||||
coloredRoundedRectangle(colorScheme.secondaryContainer.toArgb(), dp(8.dp))
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_checkable),
|
||||
coloredRectangle(transparent)
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(android.R.attr.state_empty),
|
||||
coloredRectangle(transparent)
|
||||
)
|
||||
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(),
|
||||
coloredRectangle(transparent)
|
||||
)
|
||||
}
|
||||
|
||||
spaceBarBackground = StateListDrawable().apply {
|
||||
addState(intArrayOf(android.R.attr.state_pressed),
|
||||
LayerDrawable(
|
||||
arrayOf(
|
||||
coloredRoundedRectangle(highlight, dp(32.dp)),
|
||||
coloredRoundedRectangle(highlight, dp(32.dp))
|
||||
)
|
||||
)
|
||||
)
|
||||
addState(intArrayOf(),
|
||||
coloredRoundedRectangle(highlight, dp(32.dp))
|
||||
)
|
||||
}
|
||||
|
||||
keyFeedback = ShapeDrawable().apply {
|
||||
paint.color = secondary
|
||||
shape = RoundRectShape(
|
||||
floatArrayOf(
|
||||
dp(8.dp), dp(8.dp), dp(8.dp), dp(8.dp),
|
||||
dp(8.dp), dp(8.dp), dp(8.dp), dp(8.dp),
|
||||
), null, null
|
||||
)
|
||||
|
||||
intrinsicWidth = dp(48.dp).roundToInt()
|
||||
intrinsicHeight = dp(24.dp).roundToInt()
|
||||
|
||||
setPadding(0, 0, 0, dp(50.dp).roundToInt())
|
||||
}
|
||||
|
||||
moreKeysKeyboardBackground = coloredRoundedRectangle(surface, dp(8.dp))
|
||||
popupKey = StateListDrawable().apply {
|
||||
addStateWithHighlightLayerOnPressed(highlight, intArrayOf(),
|
||||
coloredRoundedRectangle(surface, dp(8.dp))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.futo.inputmethod.latin.uix
|
||||
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.annotation.ColorInt
|
||||
|
||||
interface DynamicThemeProvider {
|
||||
val primaryKeyboardColor: Int
|
||||
|
||||
val keyboardBackground: Drawable
|
||||
val keyBackground: Drawable
|
||||
val spaceBarBackground: Drawable
|
||||
|
||||
val keyFeedback: Drawable
|
||||
|
||||
val moreKeysKeyboardBackground: Drawable
|
||||
val popupKey: Drawable
|
||||
|
||||
@ColorInt
|
||||
fun getColor(i: Int): Int?
|
||||
|
||||
fun getDrawable(i: Int): Drawable?
|
||||
|
||||
companion object {
|
||||
@ColorInt
|
||||
fun getColorOrDefault(i: Int, @ColorInt default: Int, keyAttr: TypedArray, provider: DynamicThemeProvider?): Int {
|
||||
return (provider?.getColor(i)) ?: keyAttr.getColor(i, default)
|
||||
}
|
||||
|
||||
fun getDrawableOrDefault(i: Int, keyAttr: TypedArray, provider: DynamicThemeProvider?): Drawable? {
|
||||
return (provider?.getDrawable(i)) ?: keyAttr.getDrawable(i)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.futo.inputmethod.latin.uix
|
||||
|
||||
interface DynamicThemeProviderOwner {
|
||||
fun getDrawableProvider(): DynamicThemeProvider
|
||||
}
|
73
java/src/org/futo/inputmethod/latin/uix/Settings.kt
Normal file
73
java/src/org/futo/inputmethod/latin/uix/Settings.kt
Normal file
@ -0,0 +1,73 @@
|
||||
package org.futo.inputmethod.latin.uix
|
||||
|
||||
import android.content.Context
|
||||
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.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun <T> Context.getSettingBlocking(key: Preferences.Key<T>, default: T): T {
|
||||
val context = this
|
||||
|
||||
return runBlocking {
|
||||
context.getSetting(key, default)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Context.setSettingBlocking(key: Preferences.Key<T>, value: T) {
|
||||
val context = this
|
||||
runBlocking {
|
||||
context.setSetting(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LifecycleOwner.deferGetSetting(key: Preferences.Key<T>, default: T, onObtained: (T) -> Unit): Job {
|
||||
val context = (this as Context)
|
||||
return lifecycleScope.launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
val value = context.getSetting(key, default)
|
||||
onObtained(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LifecycleOwner.deferSetSetting(key: Preferences.Key<T>, value: T): Job {
|
||||
val context = (this as Context)
|
||||
return lifecycleScope.launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
context.setSetting(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val THEME_KEY = stringPreferencesKey("activeThemeOption")
|
Loading…
x
Reference in New Issue
Block a user