Compare commits
12 Commits
test/emoji
...
test/inlin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11a41f30e4 | ||
|
|
c035e19cfc | ||
|
|
8d30403676 | ||
|
|
2886a24fcc | ||
|
|
352c98205c | ||
|
|
18c76b7195 | ||
|
|
ea0712225a | ||
|
|
1132eaf59b | ||
|
|
cba85f1c0e | ||
|
|
15dba9f33a | ||
|
|
3859528120 | ||
|
|
046d253382 |
@@ -206,6 +206,7 @@ dependencies {
|
||||
implementation(libs.mikepenz.aboutlibraries.compose)
|
||||
implementation(libs.patrickgold.compose.tooltip)
|
||||
implementation(libs.patrickgold.jetpref.datastore.model)
|
||||
ksp(libs.patrickgold.jetpref.datastore.model.processor)
|
||||
implementation(libs.patrickgold.jetpref.datastore.ui)
|
||||
implementation(libs.patrickgold.jetpref.material.ui)
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import androidx.core.os.UserManagerCompat
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.clipboard.ClipboardManager
|
||||
import dev.patrickgold.florisboard.ime.core.SubtypeManager
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
@@ -40,7 +42,11 @@ import dev.patrickgold.florisboard.lib.devtools.Flog
|
||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import dev.patrickgold.jetpref.datastore.runtime.initAndroid
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
|
||||
import org.florisboard.lib.kotlin.tryOrNull
|
||||
import org.florisboard.libnative.dummyAdd
|
||||
@@ -63,8 +69,9 @@ class FlorisApplication : Application() {
|
||||
}
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val mainHandler by lazy { Handler(mainLooper) }
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
val preferenceStoreLoaded = MutableStateFlow(false)
|
||||
|
||||
val cacheManager = lazy { CacheManager(this) }
|
||||
val clipboardManager = lazy { ClipboardManager(this) }
|
||||
@@ -80,7 +87,6 @@ class FlorisApplication : Application() {
|
||||
super.onCreate()
|
||||
FlorisApplicationReference = WeakReference(this)
|
||||
try {
|
||||
JetPref.configure(saveIntervalMs = 500)
|
||||
Flog.install(
|
||||
context = this,
|
||||
isFloggingEnabled = BuildConfig.DEBUG,
|
||||
@@ -108,7 +114,14 @@ class FlorisApplication : Application() {
|
||||
|
||||
fun init() {
|
||||
cacheDir?.deleteContentsRecursively()
|
||||
prefs.initializeBlocking(this)
|
||||
scope.launch {
|
||||
val result = FlorisPreferenceStore.initAndroid(
|
||||
context = this@FlorisApplication,
|
||||
datastoreName = FlorisPreferenceModel.NAME,
|
||||
)
|
||||
Log.i("PREFS", result.toString())
|
||||
preferenceStoreLoaded.value = true
|
||||
}
|
||||
extensionManager.value.init()
|
||||
clipboardManager.value.initializeForContext(this)
|
||||
DictionaryManager.init(this)
|
||||
|
||||
@@ -75,8 +75,8 @@ import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import dev.patrickgold.florisboard.app.FlorisAppActivity
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.devtools.DevtoolsOverlay
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.ImeUiMode
|
||||
import dev.patrickgold.florisboard.ime.clipboard.ClipboardInputLayout
|
||||
import dev.patrickgold.florisboard.ime.core.SelectSubtypePanel
|
||||
@@ -119,8 +119,9 @@ import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.isOrientationLandscape
|
||||
import org.florisboard.lib.android.isOrientationPortrait
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
import org.florisboard.lib.android.systemServiceOrNull
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
import org.florisboard.lib.kotlin.collectIn
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
@@ -246,12 +247,12 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
ims.showShortToast("Failed to find voice IME, do you have one installed?")
|
||||
ims.showShortToastSync("Failed to find voice IME, do you have one installed?")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val editorInstance by editorInstance()
|
||||
private val keyboardManager by keyboardManager()
|
||||
private val nlpManager by nlpManager()
|
||||
@@ -277,21 +278,21 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
super.onCreate()
|
||||
FlorisImeServiceReference = WeakReference(this)
|
||||
WindowCompat.setDecorFitsSystemWindows(window.window!!, false)
|
||||
subtypeManager.activeSubtypeFlow.collectLatestIn(lifecycleScope) { subtype ->
|
||||
subtypeManager.activeSubtypeFlow.collectIn(lifecycleScope) { subtype ->
|
||||
val config = Configuration(resources.configuration)
|
||||
if (prefs.localization.displayKeyboardLabelsInSubtypeLanguage.get()) {
|
||||
config.setLocale(subtype.primaryLocale.base)
|
||||
}
|
||||
resourcesContext = createConfigurationContext(config)
|
||||
}
|
||||
prefs.localization.displayKeyboardLabelsInSubtypeLanguage.observeForever { shouldSync ->
|
||||
prefs.localization.displayKeyboardLabelsInSubtypeLanguage.asFlow().collectIn(lifecycleScope) { shouldSync ->
|
||||
val config = Configuration(resources.configuration)
|
||||
if (shouldSync) {
|
||||
config.setLocale(subtypeManager.activeSubtype.primaryLocale.base)
|
||||
}
|
||||
resourcesContext = createConfigurationContext(config)
|
||||
}
|
||||
prefs.physicalKeyboard.showOnScreenKeyboard.observeForever {
|
||||
prefs.physicalKeyboard.showOnScreenKeyboard.asFlow().collectIn(lifecycleScope) {
|
||||
updateInputViewShown()
|
||||
}
|
||||
@Suppress("DEPRECATION") // We do not retrieve the wallpaper but only listen to changes
|
||||
@@ -408,7 +409,6 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
flogInfo(LogTopic.IMS_EVENTS)
|
||||
}
|
||||
isWindowShown = true
|
||||
themeManager.updateActiveTheme()
|
||||
inputFeedbackController.updateSystemPrefsState()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.service.textservice.SpellCheckerService
|
||||
import android.view.textservice.SentenceSuggestionsInfo
|
||||
import android.view.textservice.SuggestionsInfo
|
||||
import android.view.textservice.TextInfo
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
|
||||
@@ -33,7 +33,7 @@ import kotlinx.coroutines.runBlocking
|
||||
import org.florisboard.lib.kotlin.map
|
||||
|
||||
class FlorisSpellCheckerService : SpellCheckerService() {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val dictionaryManager get() = DictionaryManager.default()
|
||||
private val nlpManager by nlpManager()
|
||||
private val subtypeManager by subtypeManager()
|
||||
|
||||
@@ -57,7 +57,8 @@ import dev.patrickgold.florisboard.lib.compose.ColorPreferenceSerializer
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.lib.util.VersionName
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import dev.patrickgold.jetpref.datastore.annotations.Preferences
|
||||
import dev.patrickgold.jetpref.datastore.jetprefDataStoreOf
|
||||
import dev.patrickgold.jetpref.datastore.model.LocalTime
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceData
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceMigrationEntry
|
||||
@@ -69,9 +70,14 @@ import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.isOrientationPortrait
|
||||
import org.florisboard.lib.color.DEFAULT_GREEN
|
||||
|
||||
fun florisPreferenceModel() = JetPref.getOrCreatePreferenceModel(AppPrefs::class, ::AppPrefs)
|
||||
val FlorisPreferenceStore = jetprefDataStoreOf(FlorisPreferenceModel::class)
|
||||
|
||||
@Preferences
|
||||
abstract class FlorisPreferenceModel : PreferenceModel() {
|
||||
companion object {
|
||||
const val NAME = "florisboard-app-prefs"
|
||||
}
|
||||
|
||||
class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
val clipboard = Clipboard()
|
||||
inner class Clipboard {
|
||||
val useInternalClipboard = boolean(
|
||||
@@ -758,11 +764,11 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
},
|
||||
serializer = ColorPreferenceSerializer,
|
||||
)
|
||||
val sunriseTime = time(
|
||||
val sunriseTime = localTime(
|
||||
key = "theme__sunrise_time",
|
||||
default = LocalTime(6, 0),
|
||||
)
|
||||
val sunsetTime = time(
|
||||
val sunsetTime = localTime(
|
||||
key = "theme__sunset_time",
|
||||
default = LocalTime(18, 0),
|
||||
)
|
||||
|
||||
@@ -39,12 +39,14 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.apptheme.FlorisAppTheme
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
|
||||
import dev.patrickgold.florisboard.app.setup.NotificationPermissionState
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.compose.LocalPreviewFieldController
|
||||
@@ -59,6 +61,8 @@ import dev.patrickgold.jetpref.datastore.ui.ProvideDefaultDialogPrefStrings
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.hideAppIcon
|
||||
import org.florisboard.lib.android.showAppIcon
|
||||
import org.florisboard.lib.kotlin.collectIn
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
enum class AppTheme(val id: String) {
|
||||
AUTO("auto"),
|
||||
@@ -73,7 +77,8 @@ val LocalNavController = staticCompositionLocalOf<NavController> {
|
||||
}
|
||||
|
||||
class FlorisAppActivity : ComponentActivity() {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val appContext by appContext()
|
||||
private val cacheManager by cacheManager()
|
||||
private var appTheme by mutableStateOf(AppTheme.AUTO)
|
||||
private var showAppIcon = true
|
||||
@@ -83,37 +88,37 @@ class FlorisAppActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// Splash screen should be installed before calling super.onCreate()
|
||||
installSplashScreen().apply {
|
||||
setKeepOnScreenCondition { !prefs.datastoreReadyStatus.get() }
|
||||
setKeepOnScreenCondition { !appContext.preferenceStoreLoaded.value }
|
||||
}
|
||||
super.onCreate(savedInstanceState)
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
|
||||
prefs.other.settingsTheme.observe(this) {
|
||||
prefs.other.settingsTheme.asFlow().collectIn(lifecycleScope) {
|
||||
appTheme = it
|
||||
}
|
||||
prefs.other.settingsLanguage.observe(this) {
|
||||
prefs.other.settingsLanguage.asFlow().collectIn(lifecycleScope) {
|
||||
val config = Configuration(resources.configuration)
|
||||
val locale = if (it == "auto") FlorisLocale.default() else FlorisLocale.fromTag(it)
|
||||
config.setLocale(locale.base)
|
||||
resourcesContext = createConfigurationContext(config)
|
||||
}
|
||||
if (AndroidVersion.ATMOST_API28_P) {
|
||||
prefs.other.showAppIcon.observe(this) {
|
||||
prefs.other.showAppIcon.asFlow().collectIn(lifecycleScope) {
|
||||
showAppIcon = it
|
||||
}
|
||||
}
|
||||
|
||||
//Check if android 13+ is running and the NotificationPermission is not set
|
||||
if (AndroidVersion.ATLEAST_API33_T &&
|
||||
prefs.internal.notificationPermissionState.get() == NotificationPermissionState.NOT_SET
|
||||
) {
|
||||
// update pref value to show the setup screen again again
|
||||
prefs.internal.isImeSetUp.set(false)
|
||||
}
|
||||
|
||||
// We defer the setContent call until the datastore model is loaded, until then the splash screen stays drawn
|
||||
prefs.datastoreReadyStatus.observe(this) { isModelLoaded ->
|
||||
if (!isModelLoaded) return@observe
|
||||
val isModelLoaded = AtomicBoolean(false)
|
||||
appContext.preferenceStoreLoaded.collectIn(lifecycleScope) { loaded ->
|
||||
if (!loaded || isModelLoaded.getAndSet(true)) return@collectIn
|
||||
// Check if android 13+ is running and the NotificationPermission is not set
|
||||
if (AndroidVersion.ATLEAST_API33_T &&
|
||||
prefs.internal.notificationPermissionState.get() == NotificationPermissionState.NOT_SET
|
||||
) {
|
||||
// update pref value to show the setup screen again
|
||||
prefs.internal.isImeSetUp.set(false)
|
||||
}
|
||||
AppVersionUtils.updateVersionOnInstallAndLastUse(this, prefs)
|
||||
setContent {
|
||||
ProvideLocalizedResources(resourcesContext) {
|
||||
|
||||
@@ -29,9 +29,8 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
import dev.patrickgold.florisboard.app.AppTheme
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.color.ColorMappings
|
||||
|
||||
/*private val AmoledDarkColorPalette = darkColorScheme(
|
||||
@@ -79,7 +78,7 @@ fun getColorScheme(
|
||||
context: Context,
|
||||
theme: AppTheme,
|
||||
): ColorScheme {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val accentColor by prefs.other.accentColor.observeAsState()
|
||||
val isDark = isSystemInDarkTheme()
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
import java.util.Locale
|
||||
@@ -66,9 +67,9 @@ fun AndroidLocalesScreen() = FlorisScreen {
|
||||
out.appendLine()
|
||||
}
|
||||
}
|
||||
context.showLongToast("Exported available system locales to \"${txtFile.path}\"")
|
||||
context.showLongToastSync("Exported available system locales to \"${txtFile.path}\"")
|
||||
} catch (e: Exception) {
|
||||
context.showLongToast(
|
||||
context.showLongToastSync(
|
||||
R.string.error__snackbar_message_template,
|
||||
"error_message" to e.message.toString(),
|
||||
)
|
||||
|
||||
@@ -29,7 +29,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -40,7 +39,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.ime.keyboard.CachedLayout
|
||||
@@ -64,7 +63,7 @@ private val DateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", FlorisLocale.
|
||||
@Composable
|
||||
fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
val context = LocalContext.current
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val themeManager by context.themeManager()
|
||||
|
||||
@@ -75,7 +74,7 @@ fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
val showInlineAutofillOverlay by prefs.devtools.showInlineAutofillOverlay.observeAsState()
|
||||
|
||||
val debugLayoutResult by keyboardManager.layoutManager.debugLayoutComputationResultFlow.collectAsState()
|
||||
val themeInfo by themeManager.activeThemeInfo.observeAsState()
|
||||
val themeInfo by themeManager.activeThemeInfo.collectAsState()
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides Color.White,
|
||||
@@ -97,7 +96,7 @@ fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
if (devtoolsEnabled && showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
|
||||
DevtoolsInlineAutofillOverlay()
|
||||
}
|
||||
val loadFailure = themeInfo?.loadFailure
|
||||
val loadFailure = themeInfo.loadFailure
|
||||
if (loadFailure != null) {
|
||||
DevtoolsStylesheetFailedToLoadOverlay(loadFailure)
|
||||
}
|
||||
@@ -163,13 +162,13 @@ private fun DevtoolsLastLayoutComputationOverlay(debugLayoutResult: DebugLayoutC
|
||||
return@DevtoolsOverlayBox
|
||||
}
|
||||
DevtoolsSubGroup(title = "main") {
|
||||
PrintResult(debugLayoutResult!!.main)
|
||||
PrintResult(debugLayoutResult.main)
|
||||
}
|
||||
DevtoolsSubGroup(title = "mod") {
|
||||
PrintResult(debugLayoutResult!!.mod)
|
||||
PrintResult(debugLayoutResult.mod)
|
||||
}
|
||||
DevtoolsSubGroup(title = "ext") {
|
||||
PrintResult(debugLayoutResult!!.ext)
|
||||
PrintResult(debugLayoutResult.ext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
@@ -38,7 +39,9 @@ import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
|
||||
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
|
||||
class DebugOnPurposeCrashException : Exception(
|
||||
"Success! The app crashed purposely to display this beautiful screen we all love :)"
|
||||
@@ -52,6 +55,7 @@ fun DevtoolsScreen() = FlorisScreen {
|
||||
val context = LocalContext.current
|
||||
val navController = LocalNavController.current
|
||||
val extensionManager by context.extensionManager()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val (showDialog, setShowDialog) = remember { mutableStateOf(false) }
|
||||
|
||||
@@ -110,15 +114,17 @@ fun DevtoolsScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.devtools__reset_quick_actions_to_default__label),
|
||||
summary = stringRes(R.string.devtools__reset_quick_actions_to_default__summary),
|
||||
onClick = {
|
||||
prefs.smartbar.actionArrangement.set(QuickActionArrangement.Default)
|
||||
context.showLongToast(R.string.devtools__reset_quick_actions_to_default__toast_success)
|
||||
scope.launch {
|
||||
prefs.smartbar.actionArrangement.set(QuickActionArrangement.Default)
|
||||
}
|
||||
context.showLongToastSync(R.string.devtools__reset_quick_actions_to_default__toast_success)
|
||||
},
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
Preference(
|
||||
title = stringRes(R.string.devtools__reset_flag__label, "flag_name" to "isImeSetUp"),
|
||||
summary = stringRes(R.string.devtools__reset_flag_is_ime_set_up__summary),
|
||||
onClick = { prefs.internal.isImeSetUp.set(false) },
|
||||
onClick = { scope.launch { prefs.internal.isImeSetUp.set(false) } },
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
Preference(
|
||||
@@ -200,14 +206,14 @@ fun DevtoolsScreen() = FlorisScreen {
|
||||
title = "keyboardExtensions",
|
||||
summary = extensionManager.keyboardExtensions.internalModuleDir.absolutePath,
|
||||
onClick = {
|
||||
context.showLongToast(extensionManager.keyboardExtensions.internalModuleDir.absolutePath)
|
||||
context.showLongToastSync(extensionManager.keyboardExtensions.internalModuleDir.absolutePath)
|
||||
},
|
||||
)
|
||||
Preference(
|
||||
title = "themes",
|
||||
summary = extensionManager.themes.internalModuleDir.absolutePath,
|
||||
onClick = {
|
||||
context.showLongToast(extensionManager.themes.internalModuleDir.absolutePath)
|
||||
context.showLongToastSync(extensionManager.themes.internalModuleDir.absolutePath)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
@@ -47,6 +47,7 @@ import dev.patrickgold.florisboard.lib.compose.florisScrollbar
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.devtools.Devtools
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
|
||||
// TODO: This screen is just a quick thrown-together thing and needs further enhancing in the UI
|
||||
@Composable
|
||||
@@ -54,7 +55,7 @@ fun ExportDebugLogScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.devtools__debuglog__title)
|
||||
scrollable = false
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val clipboardManager by context.clipboardManager()
|
||||
|
||||
@@ -74,7 +75,7 @@ fun ExportDebugLogScreen() = FlorisScreen {
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
clipboardManager.addNewPlaintext(debugLog!!.joinToString("\n"))
|
||||
context.showShortToast(context.getString(R.string.devtools__debuglog__copied_to_clipboard))
|
||||
context.showShortToastSync(context.getString(R.string.devtools__debuglog__copied_to_clipboard))
|
||||
},
|
||||
modifier = Modifier,
|
||||
text = stringRes(R.string.devtools__debuglog__copy_log),
|
||||
@@ -83,7 +84,7 @@ fun ExportDebugLogScreen() = FlorisScreen {
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
clipboardManager.addNewPlaintext(formattedDebugLog!!.joinToString("\n"))
|
||||
context.showShortToast(context.getString(R.string.devtools__debuglog__copied_to_clipboard))
|
||||
context.showShortToastSync(context.getString(R.string.devtools__debuglog__copied_to_clipboard))
|
||||
},
|
||||
text = stringRes(R.string.devtools__debuglog__copy_for_github),
|
||||
enabled = debugLog != null,
|
||||
|
||||
@@ -59,7 +59,9 @@ import java.util.*
|
||||
import org.florisboard.lib.android.query
|
||||
import org.florisboard.lib.android.readToFile
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
import org.florisboard.lib.kotlin.io.parentDir
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
@@ -186,9 +188,9 @@ fun ExtensionEditFilesScreen(workspace: CacheManager.ExtEditorWorkspace<*>) = Fl
|
||||
allowOutsideDismissal = true,
|
||||
onNeutral = {
|
||||
if (file.delete()) {
|
||||
context.showShortToast("Successfully deleted")
|
||||
context.showShortToastSync("Successfully deleted")
|
||||
} else {
|
||||
context.showShortToast("Failed to delete")
|
||||
context.showShortToastSync("Failed to delete")
|
||||
}
|
||||
dialogFile = null
|
||||
version++
|
||||
@@ -196,18 +198,18 @@ fun ExtensionEditFilesScreen(workspace: CacheManager.ExtEditorWorkspace<*>) = Fl
|
||||
onConfirm = {
|
||||
val newFile = file.parentFile!!.subFile(fileNameInput).canonicalFile
|
||||
if (newFile.parentFile != file.canonicalFile.parentFile) {
|
||||
context.showLongToast("Invalid file name!")
|
||||
context.showLongToastSync("Invalid file name!")
|
||||
return@JetPrefAlertDialog
|
||||
}
|
||||
if (newFile.exists()) {
|
||||
context.showShortToast("Filename already exists.")
|
||||
context.showShortToastSync("Filename already exists.")
|
||||
return@JetPrefAlertDialog
|
||||
}
|
||||
val success = file.renameTo(newFile)
|
||||
if (success) {
|
||||
context.showShortToast("Successfully renamed")
|
||||
context.showShortToastSync("Successfully renamed")
|
||||
} else {
|
||||
context.showShortToast("Failed to rename the file.")
|
||||
context.showShortToastSync("Failed to rename the file.")
|
||||
}
|
||||
dialogFile = null
|
||||
version++
|
||||
@@ -257,13 +259,13 @@ fun ExtensionEditFilesScreen(workspace: CacheManager.ExtEditorWorkspace<*>) = Fl
|
||||
dir.mkdirs()
|
||||
val file = dir.subFile(fileName)
|
||||
if (file.parentDir != workspace.extDir.subDir(dest)) {
|
||||
context.showShortToast("Invalid file name")
|
||||
context.showShortToastSync("Invalid file name")
|
||||
} else if (file.exists()) {
|
||||
context.showShortToast("File already exists")
|
||||
context.showShortToastSync("File already exists")
|
||||
} else {
|
||||
val tempFile = result.first
|
||||
if (!tempFile.renameTo(file)) {
|
||||
context.showShortToast("Failed to rename file")
|
||||
context.showShortToastSync("Failed to rename file")
|
||||
tempFile.delete()
|
||||
}
|
||||
currentImportDest = null
|
||||
|
||||
@@ -90,6 +90,7 @@ import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefTextField
|
||||
import java.util.*
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
@@ -287,7 +288,7 @@ private fun EditScreen(
|
||||
stylesheetFile.writeText(stylesheet)
|
||||
}.onFailure {
|
||||
// TODO: better error handling
|
||||
context.showLongToast(it.message.toString())
|
||||
context.showLongToastSync(it.message.toString())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -665,7 +666,7 @@ private fun <T : ExtensionComponent> CreateComponentScreen(
|
||||
when (createFrom) {
|
||||
CreateFrom.EMPTY -> {
|
||||
if (editor.themes.any { it.id == newId.trim() }) {
|
||||
context.showLongToast("A theme with this ID already exists!")
|
||||
context.showLongToastSync("A theme with this ID already exists!")
|
||||
} else {
|
||||
val componentEditor = ThemeExtensionComponentEditor(
|
||||
id = newId.trim(),
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.ext.Extension
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionDefaults
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
|
||||
@Composable
|
||||
fun ExtensionExportScreen(id: String) {
|
||||
@@ -61,9 +62,9 @@ private fun ExportScreen(ext: Extension) = FlorisScreen {
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
runCatching { extensionManager.export(ext, uri) }.onSuccess {
|
||||
context.showLongToast(R.string.ext__export__success)
|
||||
context.showLongToastSync(R.string.ext__export__success)
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(R.string.ext__export__failure, "error_message" to error.localizedMessage)
|
||||
context.showLongToastSync(R.string.ext__export__failure, "error_message" to error.localizedMessage)
|
||||
}
|
||||
navController.popBackStack()
|
||||
},
|
||||
|
||||
@@ -61,6 +61,7 @@ import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.io.FileRegistry
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.kotlin.resultOk
|
||||
|
||||
enum class ExtensionImportScreenType(
|
||||
@@ -188,10 +189,10 @@ fun ExtensionImportScreen(type: ExtensionImportScreenType, initUuid: String?) =
|
||||
}
|
||||
}.onSuccess {
|
||||
workspace.close()
|
||||
context.showLongToast(R.string.ext__import__success)
|
||||
context.showLongToastSync(R.string.ext__import__success)
|
||||
navController.popBackStack()
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(R.string.ext__import__failure, "error_message" to error.localizedMessage)
|
||||
context.showLongToastSync(R.string.ext__import__failure, "error_message" to error.localizedMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ import dev.patrickgold.florisboard.lib.ext.Extension
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMaintainer
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.lib.io.FlorisRef
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
|
||||
@Composable
|
||||
fun ExtensionViewScreen(id: String) {
|
||||
@@ -202,7 +203,7 @@ private fun ViewScreen(ext: Extension) = FlorisScreen {
|
||||
}.onSuccess {
|
||||
navController.popBackStack()
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(
|
||||
context.showLongToastSync(
|
||||
R.string.error__snackbar_message,
|
||||
"error_message" to error.localizedMessage,
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -41,6 +42,8 @@ import androidx.core.app.ShareCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
@@ -57,11 +60,14 @@ import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.lib.io.FileRegistry
|
||||
import dev.patrickgold.florisboard.lib.io.ZipUtils
|
||||
import dev.patrickgold.jetpref.datastore.jetprefDatastoreDir
|
||||
import dev.patrickgold.jetpref.datastore.runtime.AndroidAppDataStorage
|
||||
import dev.patrickgold.jetpref.datastore.runtime.FileBasedStorage
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.android.writeFromFile
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
@@ -136,6 +142,7 @@ fun BackupScreen() = FlorisScreen {
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val cacheManager by context.cacheManager()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
var backupDestination by remember { mutableStateOf(Backup.Destination.FILE_SYS) }
|
||||
val backupFilesSelector = remember { Backup.FilesSelector() }
|
||||
@@ -155,22 +162,24 @@ fun BackupScreen() = FlorisScreen {
|
||||
context.contentResolver.writeFromFile(uri, backupWorkspace!!.zipFile)
|
||||
backupWorkspace!!.close()
|
||||
}.onSuccess {
|
||||
context.showLongToast(R.string.backup_and_restore__back_up__success)
|
||||
context.showLongToastSync(R.string.backup_and_restore__back_up__success)
|
||||
navController.popBackStack()
|
||||
}.onFailure { error ->
|
||||
flogError { error.stackTraceToString() }
|
||||
context.showLongToast(R.string.backup_and_restore__back_up__failure, "error_message" to error.message)
|
||||
context.showLongToastSync(R.string.backup_and_restore__back_up__failure, "error_message" to error.message)
|
||||
backupWorkspace = null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
fun prepareBackupWorkspace() {
|
||||
suspend fun prepareBackupWorkspace() {
|
||||
val workspace = cacheManager.backupAndRestore.new()
|
||||
if (backupFilesSelector.jetprefDatastore) {
|
||||
context.jetprefDatastoreDir.let { dir ->
|
||||
dir.copyRecursively(workspace.inputDir.subDir(dir.name))
|
||||
}
|
||||
val fileBasedStorage = workspace.inputDir
|
||||
.subDir(AndroidAppDataStorage.JETPREF_DIR_NAME)
|
||||
.subFile("${FlorisPreferenceModel.NAME}.${AndroidAppDataStorage.JETPREF_FILE_EXT}")
|
||||
.let { FileBasedStorage(it.path) }
|
||||
FlorisPreferenceStore.export(fileBasedStorage).getOrThrow()
|
||||
}
|
||||
val workspaceFilesDir = workspace.inputDir.subDir("files")
|
||||
if (backupFilesSelector.imeKeyboard) {
|
||||
@@ -225,7 +234,7 @@ fun BackupScreen() = FlorisScreen {
|
||||
backupWorkspace = workspace
|
||||
}
|
||||
|
||||
fun prepareAndPerformBackup() {
|
||||
suspend fun prepareAndPerformBackup() {
|
||||
runCatching {
|
||||
if (backupWorkspace == null || backupWorkspace!!.isClosed()) {
|
||||
prepareBackupWorkspace()
|
||||
@@ -265,7 +274,7 @@ fun BackupScreen() = FlorisScreen {
|
||||
)
|
||||
ButtonBarButton(
|
||||
onClick = {
|
||||
prepareAndPerformBackup()
|
||||
scope.launch { prepareAndPerformBackup() }
|
||||
},
|
||||
text = stringRes(R.string.action__back_up),
|
||||
enabled = backupFilesSelector.atLeastOneSelected(),
|
||||
|
||||
@@ -43,8 +43,9 @@ import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
|
||||
@@ -60,13 +61,16 @@ import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.lib.io.ZipUtils
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import dev.patrickgold.jetpref.datastore.runtime.AndroidAppDataStorage
|
||||
import dev.patrickgold.jetpref.datastore.runtime.FileBasedStorage
|
||||
import dev.patrickgold.jetpref.datastore.runtime.ImportStrategy
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.readToFile
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
|
||||
import org.florisboard.lib.kotlin.io.readJson
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
@@ -79,11 +83,6 @@ object Restore {
|
||||
const val MIN_VERSION_CODE = 64
|
||||
const val PACKAGE_NAME = "dev.patrickgold.florisboard"
|
||||
const val BACKUP_ARCHIVE_FILE_NAME = "backup.zip"
|
||||
|
||||
enum class Mode {
|
||||
MERGE,
|
||||
ERASE_AND_OVERWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -91,13 +90,12 @@ fun RestoreScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.backup_and_restore__restore__title)
|
||||
previewFieldVisible = false
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val cacheManager by context.cacheManager()
|
||||
|
||||
val restoreFilesSelector = remember { Backup.FilesSelector() }
|
||||
var restoreMode by remember { mutableStateOf(Restore.Mode.MERGE) }
|
||||
var importStrategy by remember { mutableStateOf(ImportStrategy.Merge) }
|
||||
// TODO: rememberCoroutineScope() is unusable because it provides the scope in a cancelled state, which does
|
||||
// not make sense at all. I suspect that this is a bug and once it is resolved we can use it here again.
|
||||
val restoreScope = remember { CoroutineScope(Dispatchers.Main) }
|
||||
@@ -138,7 +136,7 @@ fun RestoreScreen() = FlorisScreen {
|
||||
}
|
||||
restoreWorkspace = workspace
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(
|
||||
context.showLongToastSync(
|
||||
R.string.backup_and_restore__restore__failure,
|
||||
"error_message" to error.localizedMessage,
|
||||
)
|
||||
@@ -148,15 +146,13 @@ fun RestoreScreen() = FlorisScreen {
|
||||
|
||||
suspend fun performRestore() {
|
||||
val workspace = restoreWorkspace!!
|
||||
val shouldReset = restoreMode == Restore.Mode.ERASE_AND_OVERWRITE
|
||||
val shouldReset = importStrategy == ImportStrategy.Erase
|
||||
if (restoreFilesSelector.jetprefDatastore) {
|
||||
val datastoreFile = workspace.outputDir
|
||||
.subDir(JetPref.JETPREF_DIR_NAME)
|
||||
.subFile("${prefs.name}.${JetPref.JETPREF_FILE_EXT}")
|
||||
if (datastoreFile.exists()) {
|
||||
prefs.datastorePersistenceHandler?.loadPrefs(datastoreFile, shouldReset)
|
||||
prefs.datastorePersistenceHandler?.persistPrefs()
|
||||
}
|
||||
val fileBasedStorage = workspace.outputDir
|
||||
.subDir(AndroidAppDataStorage.JETPREF_DIR_NAME)
|
||||
.subFile("${FlorisPreferenceModel.NAME}.${AndroidAppDataStorage.JETPREF_FILE_EXT}")
|
||||
.let { FileBasedStorage(it.path) }
|
||||
FlorisPreferenceStore.import(importStrategy, fileBasedStorage).getOrThrow()
|
||||
}
|
||||
val workspaceFilesDir = workspace.outputDir.subDir("files")
|
||||
if (restoreFilesSelector.imeKeyboard) {
|
||||
@@ -275,16 +271,16 @@ fun RestoreScreen() = FlorisScreen {
|
||||
) {
|
||||
RadioListItem(
|
||||
onClick = {
|
||||
restoreMode = Restore.Mode.MERGE
|
||||
importStrategy = ImportStrategy.Merge
|
||||
},
|
||||
selected = restoreMode == Restore.Mode.MERGE,
|
||||
selected = importStrategy == ImportStrategy.Merge,
|
||||
text = stringRes(R.string.backup_and_restore__restore__mode_merge),
|
||||
)
|
||||
RadioListItem(
|
||||
onClick = {
|
||||
restoreMode = Restore.Mode.ERASE_AND_OVERWRITE
|
||||
importStrategy = ImportStrategy.Erase
|
||||
},
|
||||
selected = restoreMode == Restore.Mode.ERASE_AND_OVERWRITE,
|
||||
selected = importStrategy == ImportStrategy.Erase,
|
||||
text = stringRes(R.string.backup_and_restore__restore__mode_erase_and_overwrite),
|
||||
)
|
||||
}
|
||||
@@ -293,7 +289,7 @@ fun RestoreScreen() = FlorisScreen {
|
||||
runCatching {
|
||||
restoreDataFromFileSystemLauncher.launch("*/*")
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(
|
||||
context.showLongToastSync(
|
||||
R.string.backup_and_restore__restore__failure,
|
||||
"error_message" to error.localizedMessage,
|
||||
)
|
||||
|
||||
@@ -68,6 +68,7 @@ import dev.patrickgold.jetpref.material.ui.JetPrefTextField
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.android.stringRes
|
||||
|
||||
private val AllLanguagesLocale = FlorisLocale.from(language = "zz")
|
||||
@@ -143,16 +144,16 @@ fun UserDictionaryScreen(type: UserDictionaryType) = FlorisScreen {
|
||||
UserDictionaryType.SYSTEM -> dictionaryManager.systemUserDictionaryDatabase()
|
||||
}
|
||||
if (db == null) {
|
||||
context.showLongToast("Database handle is null, failed to import")
|
||||
context.showLongToastSync("Database handle is null, failed to import")
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
runCatching {
|
||||
db.importCombinedList(context, uri)
|
||||
}.onSuccess {
|
||||
buildUi()
|
||||
context.showLongToast(R.string.settings__udm__dictionary_import_success)
|
||||
context.showLongToastSync(R.string.settings__udm__dictionary_import_success)
|
||||
}.onFailure { error ->
|
||||
context.showLongToast("Error: ${error.localizedMessage}")
|
||||
context.showLongToastSync("Error: ${error.localizedMessage}")
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -168,15 +169,15 @@ fun UserDictionaryScreen(type: UserDictionaryType) = FlorisScreen {
|
||||
UserDictionaryType.SYSTEM -> dictionaryManager.systemUserDictionaryDatabase()
|
||||
}
|
||||
if (db == null) {
|
||||
context.showLongToast("Database handle is null, failed to export")
|
||||
context.showLongToastSync("Database handle is null, failed to export")
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
runCatching {
|
||||
db.exportCombinedList(context, uri)
|
||||
}.onSuccess {
|
||||
context.showLongToast(R.string.settings__udm__dictionary_export_success)
|
||||
context.showLongToastSync(R.string.settings__udm__dictionary_export_success)
|
||||
}.onFailure { error ->
|
||||
context.showLongToast("Error: ${error.localizedMessage}")
|
||||
context.showLongToastSync("Error: ${error.localizedMessage}")
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -41,10 +41,10 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.nlp.LanguagePackComponent
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
@@ -61,6 +61,7 @@ import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
|
||||
enum class LanguagePackManagerScreenAction(val id: String) {
|
||||
MANAGE("manage-installed-language-packs");
|
||||
@@ -75,7 +76,7 @@ fun LanguagePackManagerScreen(action: LanguagePackManagerScreenAction?) = Floris
|
||||
else -> error("LanguagePack manager screen action must not be null")
|
||||
})
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val extensionManager by context.extensionManager()
|
||||
@@ -199,7 +200,7 @@ fun LanguagePackManagerScreen(action: LanguagePackManagerScreenAction?) = Floris
|
||||
runCatching {
|
||||
extensionManager.delete(languagePackExtToDelete!!)
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(
|
||||
context.showLongToastSync(
|
||||
R.string.error__snackbar_message,
|
||||
"error_message" to error.localizedMessage,
|
||||
)
|
||||
|
||||
@@ -44,8 +44,8 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
@@ -61,7 +61,7 @@ fun SelectLocaleScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.settings__localization__subtype_select_locale)
|
||||
scrollable = false
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val navController = LocalNavController.current
|
||||
|
||||
val displayLanguageNamesIn by prefs.localization.displayLanguageNamesIn.observeAsState()
|
||||
|
||||
@@ -58,9 +58,9 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.core.SubtypeJsonConfig
|
||||
@@ -86,7 +86,6 @@ import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import kotlinx.serialization.encodeToString
|
||||
|
||||
private val SelectComponentName = ExtensionComponentName("00", "00")
|
||||
private val SelectNlpProviderId = SelectComponentName.toString()
|
||||
@@ -186,7 +185,7 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
val selectValue = stringRes(R.string.settings__localization__subtype_select_placeholder)
|
||||
val selectListValues = remember(selectValue) { listOf(selectValue) }
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val configuration = LocalConfiguration.current
|
||||
|
||||
@@ -27,8 +27,8 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHistory
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHistoryHelper
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
|
||||
@@ -52,7 +52,7 @@ fun MediaScreen() = FlorisScreen {
|
||||
previewFieldVisible = true
|
||||
iconSpaceReserved = true
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
|
||||
var shouldDelete by remember { mutableStateOf<ShouldDelete?>(null) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
@@ -68,7 +68,7 @@ fun SmartbarScreen() = FlorisScreen {
|
||||
// TODO: schedule to remove this preference in the future, but keep it for now so users
|
||||
// know why the setting is not available anymore. Also force enable it for UI display.
|
||||
SideEffect {
|
||||
prefs.smartbar.sharedActionsAutoExpandCollapse.set(true)
|
||||
// prefs.smartbar.sharedActionsAutoExpandCollapse.set(true)
|
||||
}
|
||||
SwitchPreference(
|
||||
prefs.smartbar.sharedActionsAutoExpandCollapse,
|
||||
|
||||
@@ -96,6 +96,7 @@ import dev.patrickgold.jetpref.material.ui.JetPrefDropdown
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefTextField
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefTextFieldDefaults
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
import org.florisboard.lib.android.stringRes
|
||||
import org.florisboard.lib.kotlin.curlyFormat
|
||||
import org.florisboard.lib.snygg.SnyggAnnotationRule
|
||||
@@ -406,7 +407,7 @@ private fun EditCodeValueDialog(
|
||||
}
|
||||
if (!isFlorisBoardEnabled || !isFlorisBoardSelected) {
|
||||
lastRecordingToast?.cancel()
|
||||
lastRecordingToast = context.showShortToast(
|
||||
lastRecordingToast = context.showShortToastSync(
|
||||
R.string.settings__theme_editor__code_recording_requires_default_ime_floris,
|
||||
"app_name" to context.stringRes(R.string.floris_app_name),
|
||||
)
|
||||
@@ -432,12 +433,12 @@ private fun EditCodeValueDialog(
|
||||
val defaultReceiver = keyboardManager.inputEventDispatcher.keyEventReceiver
|
||||
keyboardManager.inputEventDispatcher.keyEventReceiver = receiver
|
||||
lastRecordingToast?.cancel()
|
||||
lastRecordingToast = context.showShortToast(R.string.settings__theme_editor__code_recording_started)
|
||||
lastRecordingToast = context.showShortToastSync(R.string.settings__theme_editor__code_recording_started)
|
||||
focusRequester.requestFocus()
|
||||
onDispose {
|
||||
keyboardManager.inputEventDispatcher.keyEventReceiver = defaultReceiver
|
||||
lastRecordingToast?.cancel()
|
||||
lastRecordingToast = context.showShortToast(R.string.settings__theme_editor__code_recording_stopped)
|
||||
lastRecordingToast = context.showShortToastSync(R.string.settings__theme_editor__code_recording_stopped)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceLayout
|
||||
@@ -37,7 +37,7 @@ fun FineTuneDialog(onDismiss: () -> Unit) {
|
||||
onDismiss = onDismiss,
|
||||
contentPadding = FineTuneContentPadding,
|
||||
) {
|
||||
PreferenceLayout(florisPreferenceModel(), iconSpaceReserved = false) {
|
||||
PreferenceLayout(FlorisPreferenceStore, iconSpaceReserved = false) {
|
||||
ListPreference(
|
||||
listPref = prefs.theme.editorLevel,
|
||||
title = stringRes(R.string.settings__theme_editor__fine_tune__level),
|
||||
|
||||
@@ -30,7 +30,6 @@ import androidx.compose.material.icons.automirrored.filled.FormatAlignLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.FormatAlignRight
|
||||
import androidx.compose.material.icons.automirrored.filled.WrapText
|
||||
import androidx.compose.material.icons.filled.AttachFile
|
||||
import androidx.compose.material.icons.filled.CheckBox
|
||||
import androidx.compose.material.icons.filled.CheckBoxOutlineBlank
|
||||
import androidx.compose.material.icons.filled.FontDownload
|
||||
import androidx.compose.material.icons.filled.FormatAlignCenter
|
||||
@@ -57,7 +56,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDefinedVarValue
|
||||
@@ -121,7 +120,7 @@ internal fun SnyggValueIcon(
|
||||
modifier: Modifier = Modifier,
|
||||
spec: SnyggValueIcon.Spec = SnyggValueIcon.Normal,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val accentColor by prefs.theme.accentColor.observeAsState()
|
||||
|
||||
|
||||
@@ -70,9 +70,9 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.apptheme.Shapes
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionComponentView
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentEditor
|
||||
@@ -100,6 +100,7 @@ import dev.patrickgold.jetpref.material.ui.JetPrefTextField
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
import org.florisboard.lib.snygg.SnyggAnnotationRule
|
||||
import org.florisboard.lib.snygg.SnyggElementRule
|
||||
@@ -145,7 +146,7 @@ fun ThemeEditorScreen(
|
||||
title = stringRes(R.string.ext__editor__edit_component__title_theme)
|
||||
scrollable = false
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val themeManager by context.themeManager()
|
||||
@@ -309,14 +310,14 @@ fun ThemeEditorScreen(
|
||||
}
|
||||
|
||||
DisposableEffect(workspace.version) {
|
||||
themeManager.previewThemeInfo = ThemeManager.ThemeInfo.DEFAULT.copy(
|
||||
themeManager.previewThemeInfo.value = ThemeManager.ThemeInfo.DEFAULT.copy(
|
||||
name = extPreviewTheme(System.currentTimeMillis().toString()),
|
||||
config = editor.build(),
|
||||
stylesheet = stylesheetEditor.build(),
|
||||
loadedDir = workspace.extDir,
|
||||
)
|
||||
onDispose {
|
||||
themeManager.previewThemeInfo = null
|
||||
themeManager.previewThemeInfo.value = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +634,7 @@ private fun ComponentMetaEditorDialog(
|
||||
if (!allFieldsValid) {
|
||||
showValidationErrors = true
|
||||
} else if (id != editor.id && (workspace.editor as? ThemeExtensionEditor)?.themes?.find { it.id == id.trim() } != null) {
|
||||
context.showLongToast("A theme with this ID already exists!")
|
||||
context.showLongToastSync("A theme with this ID already exists!")
|
||||
} else {
|
||||
workspace.update {
|
||||
editor.id = id.trim()
|
||||
|
||||
@@ -29,10 +29,11 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
@@ -45,6 +46,7 @@ import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.themeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
enum class ThemeManagerScreenAction(val id: String) {
|
||||
SELECT_DAY("select-day"),
|
||||
@@ -60,10 +62,11 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
|
||||
})
|
||||
previewFieldVisible = true
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val extensionManager by context.extensionManager()
|
||||
val themeManager by context.themeManager()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val indexedThemeExtensions by extensionManager.themes.observeAsNonNullState()
|
||||
val extGroupedThemes = remember(indexedThemeExtensions) {
|
||||
@@ -83,7 +86,7 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
|
||||
val extComponentName = ExtensionComponentName(extId, componentId)
|
||||
when (action) {
|
||||
ThemeManagerScreenAction.SELECT_DAY,
|
||||
ThemeManagerScreenAction.SELECT_NIGHT -> {
|
||||
ThemeManagerScreenAction.SELECT_NIGHT -> scope.launch {
|
||||
getThemeIdPref().set(extComponentName)
|
||||
}
|
||||
}
|
||||
@@ -96,9 +99,9 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
|
||||
|
||||
content {
|
||||
DisposableEffect(activeThemeId) {
|
||||
themeManager.previewThemeId = activeThemeId
|
||||
themeManager.previewThemeId.value = activeThemeId
|
||||
onDispose {
|
||||
themeManager.previewThemeId = null
|
||||
themeManager.previewThemeId.value = null
|
||||
}
|
||||
}
|
||||
val grayColor = LocalContentColor.current.copy(alpha = 0.56f)
|
||||
|
||||
@@ -24,8 +24,8 @@ import androidx.compose.material.icons.filled.DarkMode
|
||||
import androidx.compose.material.icons.filled.LightMode
|
||||
import androidx.compose.material.icons.filled.WbTwilight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
@@ -59,8 +59,8 @@ fun ThemeScreen() = FlorisScreen {
|
||||
|
||||
@Composable
|
||||
fun ThemeManager.getThemeLabel(id: ExtensionComponentName): String {
|
||||
val configs by indexedThemeConfigs.observeAsState()
|
||||
configs?.get(id)?.let { return it.label }
|
||||
val configs by indexedThemeConfigs.collectAsState()
|
||||
configs[id]?.let { return it.label }
|
||||
return id.toString()
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -40,11 +41,11 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.FlorisAppActivity
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisBulletSpacer
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreenScope
|
||||
@@ -57,10 +58,11 @@ import dev.patrickgold.florisboard.lib.util.launchActivity
|
||||
import dev.patrickgold.florisboard.lib.util.launchUrl
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceUiScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
|
||||
|
||||
@Composable
|
||||
fun SetupScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.setup__title)
|
||||
@@ -70,7 +72,8 @@ fun SetupScreen() = FlorisScreen {
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val isFlorisBoardEnabled by InputMethodUtils.observeIsFlorisboardEnabled(foregroundOnly = true)
|
||||
val isFlorisBoardSelected by InputMethodUtils.observeIsFlorisboardSelected(foregroundOnly = true)
|
||||
@@ -78,10 +81,12 @@ fun SetupScreen() = FlorisScreen {
|
||||
|
||||
val requestNotification =
|
||||
rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
if (isGranted) {
|
||||
prefs.internal.notificationPermissionState.set(NotificationPermissionState.GRANTED)
|
||||
} else {
|
||||
prefs.internal.notificationPermissionState.set(NotificationPermissionState.DENIED)
|
||||
scope.launch {
|
||||
if (isGranted) {
|
||||
prefs.internal.notificationPermissionState.set(NotificationPermissionState.GRANTED)
|
||||
} else {
|
||||
prefs.internal.notificationPermissionState.set(NotificationPermissionState.DENIED)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +96,8 @@ fun SetupScreen() = FlorisScreen {
|
||||
context,
|
||||
navController,
|
||||
requestNotification,
|
||||
hasNotificationPermission
|
||||
hasNotificationPermission,
|
||||
scope,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -103,6 +109,7 @@ private fun FlorisScreenScope.content(
|
||||
navController: NavController,
|
||||
requestNotification: ManagedActivityResultLauncher<String, Boolean>,
|
||||
hasNotificationPermission: NotificationPermissionState,
|
||||
scope: CoroutineScope,
|
||||
) {
|
||||
|
||||
val stepState = rememberSaveable(saver = FlorisStepState.Saver) {
|
||||
@@ -158,7 +165,7 @@ private fun FlorisScreenScope.content(
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
},
|
||||
steps = steps(
|
||||
context, navController, requestNotification
|
||||
context, navController, requestNotification, scope
|
||||
),
|
||||
footer = {
|
||||
footer(context)
|
||||
@@ -189,10 +196,11 @@ private fun footer(context: Context) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PreferenceUiScope<AppPrefs>.steps(
|
||||
private fun PreferenceUiScope<FlorisPreferenceModel>.steps(
|
||||
context: Context,
|
||||
navController: NavController,
|
||||
requestNotification: ManagedActivityResultLauncher<String, Boolean>,
|
||||
scope: CoroutineScope,
|
||||
): List<FlorisStep> {
|
||||
|
||||
return listOfNotNull(
|
||||
@@ -232,7 +240,7 @@ private fun PreferenceUiScope<AppPrefs>.steps(
|
||||
StepText(stringRes(R.string.setup__finish_up__description_p1))
|
||||
StepText(stringRes(R.string.setup__finish_up__description_p2))
|
||||
StepButton(label = stringRes(R.string.setup__finish_up__finish_btn)) {
|
||||
this@steps.prefs.internal.isImeSetUp.set(true)
|
||||
scope.launch { this@steps.prefs.internal.isImeSetUp.set(true) }
|
||||
navController.navigate(Routes.Settings.Home) {
|
||||
popUpTo(Routes.Setup.Screen) {
|
||||
inclusive = true
|
||||
|
||||
@@ -74,6 +74,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.mutableStateSetOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -87,7 +88,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.ime.ImeUiMode
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
|
||||
@@ -112,9 +113,11 @@ import dev.patrickgold.florisboard.lib.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.lib.util.NetworkUtils
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.AndroidKeyguardManager
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
import org.florisboard.lib.android.systemService
|
||||
import org.florisboard.lib.snygg.SnyggQueryAttributes
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
@@ -136,7 +139,8 @@ const val CLIPBOARD_HISTORY_NUM_GRID_COLUMNS_AUTO: Int = 0
|
||||
fun ClipboardInputLayout(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
val clipboardManager by context.clipboardManager()
|
||||
val keyboardManager by context.keyboardManager()
|
||||
@@ -203,7 +207,7 @@ fun ClipboardInputLayout(
|
||||
)
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.ClipboardHeaderButton.elementName,
|
||||
onClick = { prefs.clipboard.historyEnabled.set(!historyEnabled) },
|
||||
onClick = { scope.launch { prefs.clipboard.historyEnabled.set(!historyEnabled) } },
|
||||
modifier = sizeModifier.autoMirrorForRtl(),
|
||||
enabled = !deviceLocked && !isPopupSurfaceActive(),
|
||||
) {
|
||||
@@ -583,7 +587,7 @@ fun ClipboardInputLayout(
|
||||
attributes = mapOf("action" to "yes"),
|
||||
onClick = {
|
||||
clipboardManager.clearHistory()
|
||||
context.showShortToast(R.string.clipboard__cleared_history)
|
||||
context.showShortToastSync(R.string.clipboard__cleared_history)
|
||||
showClearAllHistory = false
|
||||
isFilterRowShown = false
|
||||
},
|
||||
@@ -629,7 +633,7 @@ fun ClipboardInputLayout(
|
||||
text = stringRes(R.string.clipboard__disabled__message),
|
||||
)
|
||||
SnyggButton(FlorisImeUi.ClipboardHistoryDisabledButton.elementName,
|
||||
onClick = { prefs.clipboard.historyEnabled.set(true) },
|
||||
onClick = { scope.launch { prefs.clipboard.historyEnabled.set(true) } },
|
||||
modifier = Modifier.align(Alignment.End),
|
||||
) {
|
||||
SnyggText(
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
package dev.patrickgold.florisboard.ime.clipboard
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardHistoryDao
|
||||
@@ -44,6 +43,7 @@ import org.florisboard.lib.android.AndroidClipboardManager
|
||||
import org.florisboard.lib.android.AndroidClipboardManager_OnPrimaryClipChangedListener
|
||||
import org.florisboard.lib.android.setOrClearPrimaryClip
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
import org.florisboard.lib.android.systemService
|
||||
import org.florisboard.lib.kotlin.tryOrNull
|
||||
import java.io.Closeable
|
||||
@@ -91,7 +91,7 @@ class ClipboardManager(
|
||||
}
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val appContext by context.appContext()
|
||||
private val editorInstance by context.editorInstance()
|
||||
private val systemClipboardManager = context.systemService(AndroidClipboardManager::class)
|
||||
@@ -355,7 +355,7 @@ class ClipboardManager(
|
||||
val editorInstance by appContext.editorInstance()
|
||||
editorInstance.commitClipboardItem(item).also { result ->
|
||||
if (!result) {
|
||||
appContext.showShortToast("Failed to paste item.")
|
||||
appContext.showShortToastSync("Failed to paste item.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.apptheme.FlorisAppTheme
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
@@ -135,7 +135,7 @@ class FlorisCopyToClipboardActivity : ComponentActivity() {
|
||||
|
||||
@Composable
|
||||
private fun Content() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
ProvideLocalizedResources(this, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
val theme by prefs.other.settingsTheme.observeAsState()
|
||||
FlorisAppTheme(theme) {
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
package dev.patrickgold.florisboard.ime.core
|
||||
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.CurrencySet
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogDebug
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
|
||||
val SubtypeJsonConfig = Json {
|
||||
encodeDefaults = true
|
||||
@@ -38,8 +41,9 @@ val SubtypeJsonConfig = Json {
|
||||
* helper methods for the in-keyboard language switch process.
|
||||
*/
|
||||
class SubtypeManager(context: Context) {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val keyboardManager by context.keyboardManager()
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
private val _subtypesFlow = MutableStateFlow(listOf<Subtype>())
|
||||
val subtypesFlow = _subtypesFlow.asStateFlow()
|
||||
@@ -54,7 +58,7 @@ class SubtypeManager(context: Context) {
|
||||
private set(v) { _activeSubtypeFlow.value = v }
|
||||
|
||||
init {
|
||||
prefs.localization.subtypes.observeForever { listRaw ->
|
||||
prefs.localization.subtypes.asFlow().collectLatestIn(scope) { listRaw ->
|
||||
flogDebug { listRaw }
|
||||
val list = if (listRaw.isNotBlank()) {
|
||||
SubtypeJsonConfig.decodeFromString<List<Subtype>>(listRaw)
|
||||
@@ -66,7 +70,7 @@ class SubtypeManager(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun persistNewSubtypeList(list: List<Subtype>) {
|
||||
private fun persistNewSubtypeList(list: List<Subtype>) = scope.launch {
|
||||
val listRaw = SubtypeJsonConfig.encodeToString(list)
|
||||
prefs.localization.subtypes.set(listRaw)
|
||||
}
|
||||
@@ -78,7 +82,7 @@ class SubtypeManager(context: Context) {
|
||||
* @return The active subtype or null, if the subtype list is empty or no new active subtype
|
||||
* could be determined.
|
||||
*/
|
||||
private fun evaluateActiveSubtype(list: List<Subtype>) {
|
||||
private fun evaluateActiveSubtype(list: List<Subtype>) = scope.launch {
|
||||
val activeSubtypeId = prefs.localization.activeSubtypeId.get()
|
||||
val subtype = list.find { it.id == activeSubtypeId } ?: list.firstOrNull() ?: Subtype.DEFAULT
|
||||
if (subtype.id != activeSubtypeId) {
|
||||
@@ -184,7 +188,7 @@ class SubtypeManager(context: Context) {
|
||||
/**
|
||||
* Switch to the previous subtype in the subtype list if possible.
|
||||
*/
|
||||
fun switchToPrevSubtype() {
|
||||
fun switchToPrevSubtype() = scope.launch {
|
||||
val subtypeList = subtypes
|
||||
val cachedActiveSubtype = activeSubtype
|
||||
var triggerNextSubtype = false
|
||||
@@ -207,7 +211,7 @@ class SubtypeManager(context: Context) {
|
||||
/**
|
||||
* Switch to the next subtype in the subtype list if possible.
|
||||
*/
|
||||
fun switchToNextSubtype() {
|
||||
fun switchToNextSubtype() = scope.launch {
|
||||
val subtypeList = subtypes
|
||||
val cachedActiveSubtype = activeSubtype
|
||||
var triggerNextSubtype = false
|
||||
@@ -227,7 +231,7 @@ class SubtypeManager(context: Context) {
|
||||
activeSubtype = newActiveSubtype
|
||||
}
|
||||
|
||||
fun switchToSubtypeById(id: Long) {
|
||||
fun switchToSubtypeById(id: Long) = scope.launch {
|
||||
if (subtypes.any { it.id == id }) {
|
||||
activeSubtype = getSubtypeById(id)!!
|
||||
prefs.localization.activeSubtypeId.set(id)
|
||||
|
||||
@@ -18,7 +18,7 @@ package dev.patrickgold.florisboard.ime.dictionary
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.nlp.WordSuggestionCandidate
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
@@ -29,7 +29,7 @@ import java.lang.ref.WeakReference
|
||||
*/
|
||||
class DictionaryManager private constructor(context: Context) {
|
||||
private val applicationContext: WeakReference<Context> = WeakReference(context.applicationContext ?: context)
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
|
||||
private var florisUserDictionaryDatabase: FlorisUserDictionaryDatabase? = null
|
||||
private var systemUserDictionaryDatabase: SystemUserDictionaryDatabase? = null
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.view.KeyEvent
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||
import dev.patrickgold.florisboard.FlorisImeService
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
|
||||
@@ -43,13 +43,14 @@ import dev.patrickgold.florisboard.subtypeManager
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
|
||||
class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
companion object {
|
||||
private const val SPACE = " "
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val appContext by context.appContext()
|
||||
private val clipboardManager by context.clipboardManager()
|
||||
private val keyboardManager by context.keyboardManager()
|
||||
@@ -393,7 +394,7 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
if (text != null) {
|
||||
clipboardManager.addNewPlaintext(text.toString())
|
||||
} else {
|
||||
appContext.showShortToast("Failed to retrieve selected text requested to cut: Eiter selection state is invalid or an error occurred within the input connection.")
|
||||
appContext.showShortToastSync("Failed to retrieve selected text requested to cut: Eiter selection state is invalid or an error occurred within the input connection.")
|
||||
}
|
||||
return deleteBackwards()
|
||||
}
|
||||
@@ -411,7 +412,7 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
if (text != null) {
|
||||
clipboardManager.addNewPlaintext(text.toString())
|
||||
} else {
|
||||
appContext.showShortToast("Failed to retrieve selected text requested to copy: Eiter selection state is invalid or an error occurred within the input connection.")
|
||||
appContext.showShortToastSync("Failed to retrieve selected text requested to copy: Eiter selection state is invalid or an error occurred within the input connection.")
|
||||
}
|
||||
val activeSelection = activeContent.selection
|
||||
return setSelection(activeSelection.end, activeSelection.end)
|
||||
@@ -428,7 +429,7 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
phantomSpace.setInactive()
|
||||
return commitClipboardItem(clipboardManager.primaryClip).also { result ->
|
||||
if (!result) {
|
||||
appContext.showShortToast("Failed to paste item.")
|
||||
appContext.showShortToastSync("Failed to paste item.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.view.ViewConfiguration
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import androidx.collection.isNotEmpty
|
||||
import androidx.collection.set
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
@@ -48,7 +48,7 @@ class InputEventDispatcher private constructor(private val repeatableKeyCodes: I
|
||||
fun new(repeatableKeyCodes: IntArray = intArrayOf()) = InputEventDispatcher(repeatableKeyCodes.clone())
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
|
||||
private val pressedKeys = guardedByLock { SparseArrayCompat<PressedKeyInfo>() }
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.media.AudioManager
|
||||
import android.provider.Settings
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
@@ -46,7 +46,7 @@ class InputFeedbackController private constructor(private val ims: InputMethodSe
|
||||
fun new(ims: InputMethodService) = InputFeedbackController(ims)
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
|
||||
private val audioManager = ims.systemServiceOrNull(AudioManager::class)
|
||||
private val vibrator = ims.systemVibratorOrNull()
|
||||
|
||||
@@ -36,8 +36,7 @@ import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.smartbar.ExtendedActionsPlacement
|
||||
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyboard
|
||||
@@ -80,7 +79,7 @@ object FlorisImeSizing {
|
||||
|
||||
@Composable
|
||||
fun smartbarUiHeight(): Dp {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val smartbarEnabled by prefs.smartbar.enabled.observeAsState()
|
||||
val smartbarLayout by prefs.smartbar.layout.observeAsState()
|
||||
val extendedActionsExpanded by prefs.smartbar.extendedActionsExpanded.observeAsState()
|
||||
@@ -113,7 +112,7 @@ object FlorisImeSizing {
|
||||
|
||||
@Composable
|
||||
fun ProvideKeyboardRowBaseHeight(content: @Composable () -> Unit) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val resources = LocalContext.current.resources
|
||||
val configuration = LocalConfiguration.current
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dev.patrickgold.florisboard.FlorisImeService
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
@@ -74,7 +74,9 @@ import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.florisboard.lib.android.AndroidKeyguardManager
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.android.showLongToastSync
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
import org.florisboard.lib.android.systemService
|
||||
import org.florisboard.lib.kotlin.collectIn
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
@@ -83,7 +85,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
private val DoubleSpacePeriodMatcher = """([^.!?‽\s]\s)""".toRegex()
|
||||
|
||||
class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val appContext by context.appContext()
|
||||
private val clipboardManager by context.clipboardManager()
|
||||
private val editorInstance by context.editorInstance()
|
||||
@@ -129,21 +131,21 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
keyboardCache.clear()
|
||||
}
|
||||
}
|
||||
prefs.keyboard.numberRow.observeForever {
|
||||
prefs.keyboard.numberRow.asFlow().collectLatestIn(scope) {
|
||||
updateActiveEvaluators {
|
||||
keyboardCache.clear(KeyboardMode.CHARACTERS)
|
||||
}
|
||||
}
|
||||
prefs.keyboard.hintedNumberRowEnabled.observeForever {
|
||||
prefs.keyboard.hintedNumberRowEnabled.asFlow().collectLatestIn(scope) {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
prefs.keyboard.hintedSymbolsEnabled.observeForever {
|
||||
prefs.keyboard.hintedSymbolsEnabled.asFlow().collectLatestIn(scope) {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
prefs.keyboard.utilityKeyEnabled.observeForever {
|
||||
prefs.keyboard.utilityKeyEnabled.asFlow().collectLatestIn(scope) {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
prefs.keyboard.utilityKeyAction.observeForever {
|
||||
prefs.keyboard.utilityKeyAction.asFlow().collectLatestIn(scope) {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
activeState.collectLatestIn(scope) {
|
||||
@@ -164,10 +166,10 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
editorInstance.activeContentFlow.collectIn(scope) { content ->
|
||||
resetSuggestions(content)
|
||||
}
|
||||
prefs.devtools.enabled.observeForever {
|
||||
prefs.devtools.enabled.asFlow().collectLatestIn(scope) {
|
||||
reevaluateDebugFlags()
|
||||
}
|
||||
prefs.devtools.showDragAndDropHelpers.observeForever {
|
||||
prefs.devtools.showDragAndDropHelpers.asFlow().collectLatestIn(scope) {
|
||||
reevaluateDebugFlags()
|
||||
}
|
||||
}
|
||||
@@ -237,7 +239,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
return subtypeManager.subtypes.size > 1
|
||||
}
|
||||
|
||||
fun toggleOneHandedMode() {
|
||||
suspend fun toggleOneHandedMode() {
|
||||
prefs.keyboard.oneHandedModeEnabled.set(!prefs.keyboard.oneHandedModeEnabled.get())
|
||||
}
|
||||
|
||||
@@ -580,7 +582,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
/**
|
||||
* Handles a [KeyCode.TOGGLE_INCOGNITO_MODE] event.
|
||||
*/
|
||||
private fun handleToggleIncognitoMode() {
|
||||
private suspend fun handleToggleIncognitoMode() {
|
||||
prefs.suggestion.forceIncognitoModeFromDynamic.set(!prefs.suggestion.forceIncognitoModeFromDynamic.get())
|
||||
val newState = !activeState.isIncognitoMode
|
||||
activeState.isIncognitoMode = newState
|
||||
@@ -606,7 +608,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
private fun handleToggleAutocorrect() {
|
||||
lastToastReference.get()?.cancel()
|
||||
lastToastReference = WeakReference(
|
||||
appContext.showLongToast("Autocorrect toggle is a placeholder and not yet implemented")
|
||||
appContext.showLongToastSync("Autocorrect toggle is a placeholder and not yet implemented")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -716,14 +718,14 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
clipboardManager.primaryClip?.let { clipboardManager.deleteClip(it) }
|
||||
}
|
||||
clipboardManager.updatePrimaryClip(null)
|
||||
appContext.showShortToast(R.string.clipboard__cleared_primary_clip)
|
||||
appContext.showShortToastSync(R.string.clipboard__cleared_primary_clip)
|
||||
}
|
||||
KeyCode.TOGGLE_COMPACT_LAYOUT -> toggleOneHandedMode()
|
||||
KeyCode.COMPACT_LAYOUT_TO_LEFT -> {
|
||||
KeyCode.TOGGLE_COMPACT_LAYOUT -> scope.launch { toggleOneHandedMode() }
|
||||
KeyCode.COMPACT_LAYOUT_TO_LEFT -> scope.launch {
|
||||
prefs.keyboard.oneHandedMode.set(OneHandedMode.START)
|
||||
toggleOneHandedMode()
|
||||
}
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> {
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> scope.launch {
|
||||
prefs.keyboard.oneHandedMode.set(OneHandedMode.END)
|
||||
toggleOneHandedMode()
|
||||
}
|
||||
@@ -753,7 +755,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
}
|
||||
KeyCode.SYSTEM_PREV_INPUT_METHOD -> FlorisImeService.switchToPrevInputMethod()
|
||||
KeyCode.SYSTEM_NEXT_INPUT_METHOD -> FlorisImeService.switchToNextInputMethod()
|
||||
KeyCode.TOGGLE_SMARTBAR_VISIBILITY -> {
|
||||
KeyCode.TOGGLE_SMARTBAR_VISIBILITY -> scope.launch {
|
||||
prefs.smartbar.enabled.let { it.set(!it.get()) }
|
||||
}
|
||||
KeyCode.TOGGLE_ACTIONS_OVERFLOW -> {
|
||||
@@ -762,7 +764,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
KeyCode.TOGGLE_ACTIONS_EDITOR -> {
|
||||
activeState.isActionsEditorVisible = !activeState.isActionsEditorVisible
|
||||
}
|
||||
KeyCode.TOGGLE_INCOGNITO_MODE -> handleToggleIncognitoMode()
|
||||
KeyCode.TOGGLE_INCOGNITO_MODE -> scope.launch { handleToggleIncognitoMode() }
|
||||
KeyCode.TOGGLE_AUTOCORRECT -> handleToggleAutocorrect()
|
||||
KeyCode.UNDO -> editorInstance.performUndo()
|
||||
KeyCode.VIEW_CHARACTERS -> activeState.keyboardMode = KeyboardMode.CHARACTERS
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package dev.patrickgold.florisboard.ime.keyboard
|
||||
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
@@ -78,7 +78,7 @@ data class DebugLayoutComputationResult(
|
||||
* Class which manages layout loading and caching.
|
||||
*/
|
||||
class LayoutManager(context: Context) {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val appContext by context.appContext()
|
||||
private val extensionManager by context.extensionManager()
|
||||
private val keyboardManager by context.keyboardManager()
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.media.emoji
|
||||
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceSerializer
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
@@ -76,7 +75,7 @@ data class EmojiHistory(
|
||||
object EmojiHistoryHelper {
|
||||
private var emojiGuard = Mutex(locked = false)
|
||||
|
||||
suspend fun markEmojiUsed(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
suspend fun markEmojiUsed(prefs: FlorisPreferenceModel, emoji: Emoji): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
@@ -121,7 +120,7 @@ object EmojiHistoryHelper {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun pinEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
suspend fun pinEmoji(prefs: FlorisPreferenceModel, emoji: Emoji): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
@@ -138,7 +137,7 @@ object EmojiHistoryHelper {
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun unpinEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
suspend fun unpinEmoji(prefs: FlorisPreferenceModel, emoji: Emoji): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
@@ -155,7 +154,7 @@ object EmojiHistoryHelper {
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun moveEmoji(prefs: AppPrefs, emoji: Emoji, offset: Int) = emojiGuard.withLock {
|
||||
suspend fun moveEmoji(prefs: FlorisPreferenceModel, emoji: Emoji, offset: Int): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get() || offset == 0) {
|
||||
return
|
||||
}
|
||||
@@ -175,7 +174,7 @@ object EmojiHistoryHelper {
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun removeEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
suspend fun removeEmoji(prefs: FlorisPreferenceModel, emoji: Emoji): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
@@ -195,7 +194,7 @@ object EmojiHistoryHelper {
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun deleteHistory(prefs: AppPrefs) = emojiGuard.withLock {
|
||||
suspend fun deleteHistory(prefs: FlorisPreferenceModel): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
@@ -203,7 +202,7 @@ object EmojiHistoryHelper {
|
||||
prefs.emoji.historyData.set(EmojiHistory(pinned = dataMut.pinned, listOf()))
|
||||
}
|
||||
|
||||
suspend fun deletePinned(prefs: AppPrefs) = emojiGuard.withLock {
|
||||
suspend fun deletePinned(prefs: FlorisPreferenceModel): Unit = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -46,8 +45,6 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.PushPin
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.TabRowDefaults
|
||||
@@ -83,7 +80,7 @@ import androidx.compose.ui.window.Popup
|
||||
import androidx.emoji2.text.EmojiCompat
|
||||
import androidx.emoji2.widget.EmojiTextView
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
@@ -133,7 +130,7 @@ fun EmojiPaletteView(
|
||||
fullEmojiMappings: EmojiData,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val editorInstance by context.editorInstance()
|
||||
val keyboardManager by context.keyboardManager()
|
||||
@@ -497,7 +494,7 @@ private fun EmojiHistoryPopup(
|
||||
onHistoryAction: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val scope = rememberCoroutineScope()
|
||||
val emojiKeyHeight = FlorisImeSizing.smartbarHeight
|
||||
val context = LocalContext.current
|
||||
|
||||
@@ -20,7 +20,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.stream.Collectors
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorContent
|
||||
import dev.patrickgold.florisboard.ime.nlp.EmojiSuggestionCandidate
|
||||
@@ -41,7 +41,7 @@ import io.github.reactivecircus.cache4k.Cache
|
||||
class EmojiSuggestionProvider(private val context: Context) : SuggestionProvider {
|
||||
override val providerId = "org.florisboard.nlp.providers.emoji"
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val lettersRegex = "^[A-Za-z]*$".toRegex()
|
||||
|
||||
private val cachedEmojiMappings = Cache.Builder().build<FlorisLocale, EmojiDataBySkinTone>()
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.content.Context
|
||||
import android.os.SystemClock
|
||||
import android.util.LruCache
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
|
||||
@@ -43,8 +43,8 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
import org.florisboard.lib.kotlin.guardedByLock
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.properties.Delegates
|
||||
@@ -54,7 +54,7 @@ private const val BLANK_STR_PATTERN = "^\\s*$"
|
||||
class NlpManager(context: Context) {
|
||||
private val blankStrRegex = Regex(BLANK_STR_PATTERN)
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val clipboardManager by context.clipboardManager()
|
||||
private val editorInstance by context.editorInstance()
|
||||
private val keyboardManager by context.keyboardManager()
|
||||
@@ -93,13 +93,13 @@ class NlpManager(context: Context) {
|
||||
clipboardManager.primaryClipFlow.collectLatestIn(scope) {
|
||||
assembleCandidates()
|
||||
}
|
||||
prefs.suggestion.enabled.observeForever {
|
||||
prefs.suggestion.enabled.asFlow().collectLatestIn(scope) {
|
||||
assembleCandidates()
|
||||
}
|
||||
prefs.clipboard.suggestionEnabled.observeForever {
|
||||
prefs.clipboard.suggestionEnabled.asFlow().collectLatestIn(scope) {
|
||||
assembleCandidates()
|
||||
}
|
||||
prefs.emoji.suggestionEnabled.observeForever {
|
||||
prefs.emoji.suggestionEnabled.asFlow().collectLatestIn(scope) {
|
||||
assembleCandidates()
|
||||
}
|
||||
subtypeManager.activeSubtypeFlow.collectLatestIn(scope) { subtype ->
|
||||
@@ -317,8 +317,10 @@ class NlpManager(context: Context) {
|
||||
}*/
|
||||
val isSelection = editorInstance.activeContent.selection.isSelectionMode
|
||||
val isExpanded = list1.isNullOrEmpty() && list2.isNullOrEmpty() || isSelection
|
||||
prefs.smartbar.sharedActionsExpandWithAnimation.set(false)
|
||||
prefs.smartbar.sharedActionsExpanded.set(isExpanded)
|
||||
scope.launch {
|
||||
prefs.smartbar.sharedActionsExpandWithAnimation.set(false)
|
||||
prefs.smartbar.sharedActionsExpanded.set(isExpanded)
|
||||
}
|
||||
}
|
||||
|
||||
fun addToDebugOverlay(word: String, info: SpellingResult) {
|
||||
|
||||
@@ -26,14 +26,16 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.ZoomOutMap
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggIconButton
|
||||
@@ -44,7 +46,8 @@ fun RowScope.OneHandedPanel(
|
||||
panelSide: OneHandedMode,
|
||||
weight: Float,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val scope = rememberCoroutineScope()
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
|
||||
SnyggColumn(
|
||||
@@ -58,8 +61,10 @@ fun RowScope.OneHandedPanel(
|
||||
SnyggIconButton(
|
||||
FlorisImeUi.OneHandedPanelButton.elementName,
|
||||
onClick = {
|
||||
inputFeedbackController.keyPress()
|
||||
prefs.keyboard.oneHandedModeEnabled.set(false)
|
||||
scope.launch {
|
||||
inputFeedbackController.keyPress()
|
||||
prefs.keyboard.oneHandedModeEnabled.set(false)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -74,8 +79,10 @@ fun RowScope.OneHandedPanel(
|
||||
SnyggIconButton(
|
||||
FlorisImeUi.OneHandedPanelButton.elementName,
|
||||
onClick = {
|
||||
inputFeedbackController.keyPress()
|
||||
prefs.keyboard.oneHandedMode.set(panelSide)
|
||||
scope.launch {
|
||||
inputFeedbackController.keyPress()
|
||||
prefs.keyboard.oneHandedMode.set(panelSide)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import dev.patrickgold.florisboard.ime.keyboard.Key
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import org.florisboard.lib.snygg.SnyggQueryAttributes
|
||||
@@ -58,7 +59,7 @@ fun PopupBaseBox(
|
||||
.align(Alignment.TopCenter),
|
||||
) {
|
||||
SnyggText(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
modifier = Modifier.align(Alignment.Center).zIndex(100f),
|
||||
text = label,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.zIndex
|
||||
import dev.patrickgold.florisboard.ime.keyboard.ComputingEvaluator
|
||||
import dev.patrickgold.florisboard.ime.keyboard.DefaultComputingEvaluator
|
||||
import dev.patrickgold.florisboard.ime.keyboard.Key
|
||||
@@ -38,6 +39,7 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeImageVector
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeLabel
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSet
|
||||
import dev.patrickgold.florisboard.ime.smartbar.Temp
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyHintConfiguration
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKey
|
||||
@@ -452,11 +454,12 @@ class PopupUiController(
|
||||
FlorisImeUi.Attr.Mode to evaluator.keyboard.mode.toString(),
|
||||
FlorisImeUi.Attr.ShiftState to evaluator.state.inputShiftState.toString(),
|
||||
)
|
||||
Temp = !(baseRenderInfo != null || extRenderInfo != null)
|
||||
baseRenderInfo?.let { renderInfo ->
|
||||
PopupBaseBox(
|
||||
modifier = Modifier
|
||||
.requiredSize(renderInfo.bounds.size.toDpSize())
|
||||
.absoluteOffset { renderInfo.bounds.topLeft.toIntOffset() },
|
||||
.absoluteOffset { renderInfo.bounds.topLeft.toIntOffset() }.zIndex(100f),
|
||||
attributes = attributes,
|
||||
key = renderInfo.key,
|
||||
shouldIndicateExtendedPopups = renderInfo.shouldIndicateExtendedPopups && extRenderInfo == null,
|
||||
|
||||
@@ -20,7 +20,6 @@ import androidx.compose.foundation.gestures.awaitEachGesture
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.width
|
||||
@@ -40,7 +39,7 @@ import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.nlp.ClipboardSuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
@@ -62,7 +61,7 @@ val CandidatesRowScrollbarHeight = 2.dp
|
||||
|
||||
@Composable
|
||||
fun CandidatesRow(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val nlpManager by context.nlpManager()
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.smartbar
|
||||
|
||||
import android.graphics.PixelFormat
|
||||
import android.os.Build
|
||||
import android.view.SurfaceView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@@ -32,16 +35,18 @@ import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInParent
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.forEach
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofillSuggestion
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.toIntOffset
|
||||
import org.florisboard.lib.snygg.SnyggPropertySet
|
||||
import org.florisboard.lib.snygg.SnyggSinglePropertySet
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggThemeQuery
|
||||
|
||||
var CachedInlineSuggestionsChipStyleSet: SnyggSinglePropertySet? = null
|
||||
|
||||
var Temp: Boolean = false
|
||||
|
||||
@Composable
|
||||
fun InlineSuggestionsStyleCache() {
|
||||
val chipStyleSet = rememberSnyggThemeQuery(FlorisImeUi.InlineAutofillChip.elementName)
|
||||
@@ -59,13 +64,16 @@ fun InlineSuggestionsUi(
|
||||
val scrollState = rememberScrollState()
|
||||
val almostEmptyRect = remember { android.graphics.Rect(0, 0, 1, 1) }
|
||||
|
||||
val backgroundColor = rememberSnyggThemeQuery(FlorisImeUi.SmartbarCandidatesRow.elementName).background()
|
||||
|
||||
Row(
|
||||
modifier
|
||||
.fillMaxSize()
|
||||
.florisHorizontalScroll(
|
||||
state = scrollState,
|
||||
scrollbarHeight = CandidatesRowScrollbarHeight,
|
||||
),
|
||||
)
|
||||
.background(backgroundColor),
|
||||
) {
|
||||
val xMin = scrollState.value
|
||||
val xMax = scrollState.value + scrollState.viewportSize
|
||||
@@ -73,6 +81,16 @@ fun InlineSuggestionsUi(
|
||||
if (inlineSuggestion.view == null) {
|
||||
continue
|
||||
}
|
||||
//inlineSuggestion.view.background = ColorDrawable(backgroundColor.toArgb())
|
||||
inlineSuggestion.view.forEach {
|
||||
with (it as SurfaceView) {
|
||||
//this.setBackgroundColor(backgroundColor.toArgb())
|
||||
setZOrderOnTop(false)
|
||||
holder.setFormat(PixelFormat.OPAQUE)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
var chipPos by remember { mutableStateOf(IntOffset.Zero) }
|
||||
AndroidView(
|
||||
modifier = Modifier.onGloballyPositioned { chipPos = it.positionInParent().toIntOffset() },
|
||||
|
||||
@@ -24,7 +24,6 @@ import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
@@ -43,6 +42,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
@@ -52,7 +52,7 @@ import androidx.compose.ui.graphics.isUnspecified
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionButton
|
||||
@@ -65,6 +65,7 @@ import dev.patrickgold.florisboard.lib.compose.verticalTween
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.vectorResource
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
@@ -89,7 +90,7 @@ private val NoAnimationTween = tween<Float>(0)
|
||||
|
||||
@Composable
|
||||
fun Smartbar() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val smartbarEnabled by prefs.smartbar.enabled.observeAsState()
|
||||
val extendedActionsPlacement by prefs.smartbar.extendedActionsPlacement.observeAsState()
|
||||
|
||||
@@ -138,10 +139,12 @@ fun Smartbar() {
|
||||
|
||||
@Composable
|
||||
private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val activeEvaluator by keyboardManager.activeEvaluator.collectAsState()
|
||||
val nlpManager by context.nlpManager()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val inlineSuggestions by NlpInlineAutofill.suggestions.collectAsState()
|
||||
LaunchedEffect(inlineSuggestions) {
|
||||
@@ -164,7 +167,9 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
if (/* was */ sharedActionsExpanded) {
|
||||
keyboardManager.activeState.isActionsOverflowVisible = false
|
||||
}
|
||||
prefs.smartbar.sharedActionsExpanded.set(!sharedActionsExpanded)
|
||||
scope.launch {
|
||||
prefs.smartbar.sharedActionsExpanded.set(!sharedActionsExpanded)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.sizeIn(maxHeight = FlorisImeSizing.smartbarHeight).aspectRatio(1f)
|
||||
) {
|
||||
@@ -244,7 +249,9 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
if (/* was */ extendedActionsExpanded) {
|
||||
keyboardManager.activeState.isActionsOverflowVisible = false
|
||||
}
|
||||
prefs.smartbar.extendedActionsExpanded.set(!extendedActionsExpanded)
|
||||
scope.launch {
|
||||
prefs.smartbar.extendedActionsExpanded.set(!extendedActionsExpanded)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.sizeIn(maxHeight = FlorisImeSizing.smartbarHeight).aspectRatio(1f)
|
||||
) {
|
||||
@@ -304,7 +311,9 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
|
||||
SideEffect {
|
||||
if (!shouldAnimate) {
|
||||
prefs.smartbar.sharedActionsExpandWithAnimation.set(true)
|
||||
scope.launch {
|
||||
prefs.smartbar.sharedActionsExpandWithAnimation.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,7 +368,7 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
|
||||
@Composable
|
||||
private fun SmartbarSecondaryRow(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val smartbarLayout by prefs.smartbar.layout.observeAsState()
|
||||
val secondaryRowStyle = rememberSnyggThemeQuery(FlorisImeUi.SmartbarExtendedActionsRow.elementName)
|
||||
val windowStyle = rememberSnyggThemeQuery(FlorisImeUi.Window.elementName)
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
|
||||
@@ -40,6 +39,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -52,7 +52,7 @@ import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.toSize
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
@@ -60,8 +60,8 @@ import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.toIntOffset
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggIconButton
|
||||
@@ -74,8 +74,9 @@ private val DragMarkerAction = QuickAction.InsertKey(TextKeyData(code = KeyCode.
|
||||
|
||||
@Composable
|
||||
fun QuickActionsEditorPanel() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
// We get the current arrangement once and do not observe on purpose
|
||||
@@ -235,7 +236,9 @@ fun QuickActionsEditorPanel() {
|
||||
dynamicActions.filter { it != NoopAction && it != DragMarkerAction },
|
||||
hiddenActions.filter { it != NoopAction && it != DragMarkerAction },
|
||||
)
|
||||
prefs.smartbar.actionArrangement.set(newActionArrangement)
|
||||
scope.launch {
|
||||
prefs.smartbar.actionArrangement.set(newActionArrangement)
|
||||
}
|
||||
if (keyboardManager.activeState.isActionsEditorVisible) {
|
||||
keyboardManager.activeState.isActionsEditorVisible = false
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
@@ -42,7 +42,7 @@ import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
@Composable
|
||||
fun QuickActionsOverflowPanel() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.smartbar.quickaction
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -28,7 +29,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
@@ -37,12 +38,13 @@ import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
|
||||
internal val ToggleOverflowPanelAction = QuickAction.InsertKey(TextKeyData.TOGGLE_ACTIONS_OVERFLOW)
|
||||
|
||||
@SuppressLint("UnusedBoxWithConstraintsScope")
|
||||
@Composable
|
||||
fun QuickActionsRow(
|
||||
elementName: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) = with(LocalDensity.current) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.smartbar.IncognitoDisplayMode
|
||||
import dev.patrickgold.florisboard.ime.smartbar.InlineSuggestionsStyleCache
|
||||
import dev.patrickgold.florisboard.ime.smartbar.Smartbar
|
||||
@@ -49,7 +49,7 @@ fun TextInputLayout(
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
|
||||
val state by keyboardManager.activeState.collectAsState()
|
||||
val evaluator by keyboardManager.activeEvaluator.collectAsState()
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package dev.patrickgold.florisboard.ime.text.gestures
|
||||
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.nlp.WordSuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKey
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
@@ -39,7 +39,7 @@ class GlideTypingManager(context: Context) : GlideTypingGesture.Listener {
|
||||
private const val MAX_SUGGESTION_COUNT = 8
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val keyboardManager by context.keyboardManager()
|
||||
private val nlpManager by context.nlpManager()
|
||||
private val subtypeManager by context.subtypeManager()
|
||||
|
||||
@@ -19,7 +19,7 @@ package dev.patrickgold.florisboard.ime.text.gestures
|
||||
import android.view.MotionEvent
|
||||
import android.view.VelocityTracker
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.lib.Pointer
|
||||
import dev.patrickgold.florisboard.lib.PointerMap
|
||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||
@@ -39,7 +39,7 @@ abstract class SwipeGesture {
|
||||
* @property listener The listener to report detected swipes to.
|
||||
*/
|
||||
class Detector(private val listener: Listener) {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
|
||||
var isEnabled: Boolean = true
|
||||
private var pointerMap: PointerMap<GesturePointer> = PointerMap { GesturePointer() }
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.text.keyboard
|
||||
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.ime.keyboard.AbstractKeyData
|
||||
import dev.patrickgold.florisboard.ime.keyboard.ComputingEvaluator
|
||||
import dev.patrickgold.florisboard.ime.keyboard.Key
|
||||
@@ -246,7 +246,7 @@ class TextKey(override val data: AbstractKeyData) : Key(data) {
|
||||
else -> null
|
||||
}
|
||||
} else if (!data.isSpaceKey() || data.type == KeyType.NUMERIC) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
computedPopups.getPopupKeys(prefs.keyboard.keyHintConfiguration()).hint.let { hintData ->
|
||||
if (hintData?.isSpaceKey() == false) {
|
||||
hintedLabel = hintData.asString(isForDisplay = true)
|
||||
|
||||
@@ -56,7 +56,7 @@ import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.toSize
|
||||
import dev.patrickgold.florisboard.FlorisImeService
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.glideTypingManager
|
||||
import dev.patrickgold.florisboard.ime.input.InputEventDispatcher
|
||||
@@ -104,7 +104,7 @@ fun TextKeyboardLayout(
|
||||
evaluator: ComputingEvaluator,
|
||||
isPreview: Boolean = false,
|
||||
): Unit = with(LocalDensity.current) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val context = LocalContext.current
|
||||
val configuration = LocalConfiguration.current
|
||||
val glideTypingManager by context.glideTypingManager()
|
||||
@@ -132,7 +132,7 @@ fun TextKeyboardLayout(
|
||||
controller.onTouchEventInternal(event)
|
||||
controller.popupUiController.hide()
|
||||
event.recycle()
|
||||
} catch (e: Throwable) {
|
||||
} catch (_: Throwable) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
@@ -337,7 +337,7 @@ private fun TextKeyButton(
|
||||
key.label?.let { label ->
|
||||
var customLabel = label
|
||||
if (key.computedData.code == KeyCode.SPACE) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val spaceBarMode by prefs.keyboard.spaceBarMode.observeAsState()
|
||||
when (spaceBarMode) {
|
||||
SpaceBarMode.NOTHING -> return@let
|
||||
@@ -385,7 +385,7 @@ private fun TextKeyButton(
|
||||
private class TextKeyboardLayoutController(
|
||||
context: Context,
|
||||
) : SwipeGesture.Listener, GlideTypingGesture.Listener {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val editorInstance by context.editorInstance()
|
||||
private val keyboardManager by context.keyboardManager()
|
||||
|
||||
|
||||
@@ -27,13 +27,10 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.themeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.SnyggAttributes
|
||||
import org.florisboard.lib.snygg.SnyggQueryAttributes
|
||||
import org.florisboard.lib.snygg.ui.ProvideSnyggTheme
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggTheme
|
||||
|
||||
@@ -52,10 +49,10 @@ fun FlorisImeTheme(content: @Composable () -> Unit) {
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val themeManager by context.themeManager()
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val prefs by FlorisPreferenceStore
|
||||
val accentColor by prefs.theme.accentColor.observeAsState()
|
||||
|
||||
val activeThemeInfo by themeManager.activeThemeInfo.observeAsNonNullState()
|
||||
val activeThemeInfo by themeManager.activeThemeInfo.collectAsState()
|
||||
val activeConfig = remember(activeThemeInfo) { activeThemeInfo.config }
|
||||
val activeStyle = remember(activeThemeInfo) { activeThemeInfo.stylesheet }
|
||||
|
||||
|
||||
@@ -39,10 +39,8 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.smartbar.CachedInlineSuggestionsChipStyleSet
|
||||
@@ -52,70 +50,67 @@ import dev.patrickgold.florisboard.lib.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.lib.io.ZipUtils
|
||||
import dev.patrickgold.florisboard.lib.util.TimeUtils.javaLocalTime
|
||||
import dev.patrickgold.florisboard.lib.util.ViewUtils
|
||||
import java.time.LocalTime
|
||||
import java.util.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.florisboard.lib.kotlin.collectIn
|
||||
import org.florisboard.lib.kotlin.io.FsDir
|
||||
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
import org.florisboard.lib.snygg.SnyggStylesheet
|
||||
import org.florisboard.lib.snygg.value.SnyggStaticColorValue
|
||||
import kotlin.properties.Delegates
|
||||
import java.time.LocalTime
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Core class which manages the keyboard theme. Note, that this does not affect the UI theme of the
|
||||
* Settings Activities.
|
||||
*/
|
||||
class ThemeManager(context: Context) {
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val prefs by FlorisPreferenceStore
|
||||
private val appContext by context.appContext()
|
||||
private val extensionManager by context.extensionManager()
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
|
||||
private val _indexedThemeConfigs = MutableLiveData(mapOf<ExtensionComponentName, ThemeExtensionComponent>())
|
||||
val indexedThemeConfigs: LiveData<Map<ExtensionComponentName, ThemeExtensionComponent>> get() = _indexedThemeConfigs
|
||||
var previewThemeId: ExtensionComponentName? by Delegates.observable(null) { _, _, _ ->
|
||||
updateActiveTheme()
|
||||
}
|
||||
var previewThemeInfo: ThemeInfo? by Delegates.observable(null) { _, _, _ ->
|
||||
updateActiveTheme()
|
||||
}
|
||||
private val _indexedThemeConfigs = MutableStateFlow(mapOf<ExtensionComponentName, ThemeExtensionComponent>())
|
||||
val indexedThemeConfigs get() = _indexedThemeConfigs.asStateFlow()
|
||||
val previewThemeId = MutableStateFlow<ExtensionComponentName?>(null)
|
||||
val previewThemeInfo = MutableStateFlow<ThemeInfo?>(null)
|
||||
val wallpaperChangedCounter = MutableStateFlow(0)
|
||||
|
||||
private val cachedThemeInfos = mutableListOf<ThemeInfo>()
|
||||
private val activeThemeGuard = Mutex(locked = false)
|
||||
private val _activeThemeInfo = MutableLiveData(ThemeInfo.DEFAULT)
|
||||
val activeThemeInfo: LiveData<ThemeInfo> get() = _activeThemeInfo
|
||||
private val _activeThemeInfo = MutableStateFlow(ThemeInfo.DEFAULT)
|
||||
val activeThemeInfo get() = _activeThemeInfo.asStateFlow()
|
||||
|
||||
init {
|
||||
extensionManager.themes.observeForever { themeExtensions ->
|
||||
val map = buildMap {
|
||||
_indexedThemeConfigs.value = buildMap {
|
||||
for (themeExtension in themeExtensions) {
|
||||
for (themeComponent in themeExtension.themes) {
|
||||
put(ExtensionComponentName(themeExtension.meta.id, themeComponent.id), themeComponent)
|
||||
}
|
||||
}
|
||||
}
|
||||
_indexedThemeConfigs.postValue(map)
|
||||
}
|
||||
indexedThemeConfigs.observeForever {
|
||||
updateActiveTheme {
|
||||
cachedThemeInfos.clear()
|
||||
}
|
||||
indexedThemeConfigs.collectIn(scope) {
|
||||
updateActiveTheme { cachedThemeInfos.clear() }
|
||||
}
|
||||
prefs.theme.mode.observeForever {
|
||||
updateActiveTheme()
|
||||
}
|
||||
prefs.theme.dayThemeId.observeForever {
|
||||
updateActiveTheme()
|
||||
}
|
||||
prefs.theme.nightThemeId.observeForever {
|
||||
combine(
|
||||
prefs.theme.mode.asFlow(),
|
||||
prefs.theme.dayThemeId.asFlow(),
|
||||
prefs.theme.nightThemeId.asFlow(),
|
||||
previewThemeId,
|
||||
previewThemeInfo,
|
||||
wallpaperChangedCounter,
|
||||
) {}.collectIn(scope) {
|
||||
updateActiveTheme()
|
||||
}
|
||||
}
|
||||
@@ -124,56 +119,54 @@ class ThemeManager(context: Context) {
|
||||
* Updates the current theme ref and loads the corresponding theme, as well as notifies all
|
||||
* callback receivers about the new theme.
|
||||
*/
|
||||
fun updateActiveTheme(action: () -> Unit = { }) = scope.launch {
|
||||
activeThemeGuard.withLock {
|
||||
action()
|
||||
previewThemeInfo?.let { previewThemeInfo ->
|
||||
_activeThemeInfo.postValue(previewThemeInfo)
|
||||
return@withLock
|
||||
}
|
||||
val activeName = evaluateActiveThemeName()
|
||||
val cachedInfo = cachedThemeInfos.find { it.name == activeName }
|
||||
if (cachedInfo != null) {
|
||||
_activeThemeInfo.postValue(cachedInfo)
|
||||
return@withLock
|
||||
}
|
||||
val themeExt = extensionManager.getExtensionById(activeName.extensionId) as? ThemeExtension
|
||||
val themeExtRef = themeExt?.sourceRef
|
||||
if (themeExtRef == null) {
|
||||
return@withLock
|
||||
}
|
||||
val themeConfig = themeExt.themes.find { it.id == activeName.componentId }
|
||||
if (themeConfig == null) {
|
||||
return@withLock
|
||||
}
|
||||
// TODO: loaded dir is implemented already...
|
||||
// TODO: this leaks the loaded dir, but at least the state is not kaputt from compose viewpoint
|
||||
val loadedDir = appContext.cacheDir.subDir("loaded").subDir(UUID.randomUUID().toString())
|
||||
runCatching {
|
||||
loadedDir.mkdirs()
|
||||
loadedDir.deleteContentsRecursively()
|
||||
ZipUtils.unzip(appContext, themeExtRef, loadedDir).getOrThrow()
|
||||
flogInfo { "Loaded extension ${themeExt.meta.id} into $loadedDir" }
|
||||
val stylesheetFile = loadedDir.subFile(themeConfig.stylesheetPath())
|
||||
val stylesheetJson = stylesheetFile.readText()
|
||||
SnyggStylesheet.fromJson(stylesheetJson).getOrThrow()
|
||||
}.fold(
|
||||
onSuccess = { newStylesheet ->
|
||||
val newInfo = ThemeInfo(activeName, themeConfig, newStylesheet, loadedDir, null)
|
||||
cachedThemeInfos.add(newInfo)
|
||||
_activeThemeInfo.postValue(newInfo)
|
||||
},
|
||||
onFailure = { cause ->
|
||||
_activeThemeInfo.postValue(ThemeInfo.DEFAULT.copy(
|
||||
loadFailure = LoadFailure(themeExt.meta, themeConfig, cause)
|
||||
))
|
||||
},
|
||||
)
|
||||
suspend fun updateActiveTheme(action: () -> Unit = { }) = activeThemeGuard.withLock {
|
||||
action()
|
||||
previewThemeInfo.value?.let { previewThemeInfo ->
|
||||
_activeThemeInfo.value = previewThemeInfo
|
||||
return@withLock
|
||||
}
|
||||
val activeName = evaluateActiveThemeName()
|
||||
val cachedInfo = cachedThemeInfos.find { it.name == activeName }
|
||||
if (cachedInfo != null) {
|
||||
_activeThemeInfo.value = cachedInfo
|
||||
return@withLock
|
||||
}
|
||||
val themeExt = extensionManager.getExtensionById(activeName.extensionId) as? ThemeExtension
|
||||
val themeExtRef = themeExt?.sourceRef
|
||||
if (themeExtRef == null) {
|
||||
return@withLock
|
||||
}
|
||||
val themeConfig = themeExt.themes.find { it.id == activeName.componentId }
|
||||
if (themeConfig == null) {
|
||||
return@withLock
|
||||
}
|
||||
// TODO: loaded dir is implemented already...
|
||||
// TODO: this leaks the loaded dir, but at least the state is not kaputt from compose viewpoint
|
||||
val loadedDir = appContext.cacheDir.subDir("loaded").subDir(UUID.randomUUID().toString())
|
||||
runCatching {
|
||||
loadedDir.mkdirs()
|
||||
loadedDir.deleteContentsRecursively()
|
||||
ZipUtils.unzip(appContext, themeExtRef, loadedDir).getOrThrow()
|
||||
flogInfo { "Loaded extension ${themeExt.meta.id} into $loadedDir" }
|
||||
val stylesheetFile = loadedDir.subFile(themeConfig.stylesheetPath())
|
||||
val stylesheetJson = stylesheetFile.readText()
|
||||
SnyggStylesheet.fromJson(stylesheetJson).getOrThrow()
|
||||
}.fold(
|
||||
onSuccess = { newStylesheet ->
|
||||
val newInfo = ThemeInfo(activeName, themeConfig, newStylesheet, loadedDir, null)
|
||||
cachedThemeInfos.add(newInfo)
|
||||
_activeThemeInfo.value = newInfo
|
||||
},
|
||||
onFailure = { cause ->
|
||||
_activeThemeInfo.value = ThemeInfo.DEFAULT.copy(
|
||||
loadFailure = LoadFailure(themeExt.meta, themeConfig, cause)
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun evaluateActiveThemeName(): ExtensionComponentName {
|
||||
previewThemeId?.let { return it }
|
||||
previewThemeId.value?.let { return it }
|
||||
return when (prefs.theme.mode.get()) {
|
||||
ThemeMode.ALWAYS_DAY -> {
|
||||
prefs.theme.dayThemeId.get()
|
||||
@@ -202,10 +195,9 @@ class ThemeManager(context: Context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new inline suggestion UI bundle based on the attributes of the given [style].
|
||||
* Creates a new inline suggestion UI bundle.
|
||||
*
|
||||
* @param context The context of the parent view/controller.
|
||||
* @param style The style set which is responsible for styling the chips.
|
||||
*
|
||||
* @return A bundle containing all necessary attributes for the inline suggestion views to properly display.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogDebug
|
||||
import dev.patrickgold.florisboard.themeManager
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
||||
class WallpaperChangeReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
@@ -29,7 +30,8 @@ class WallpaperChangeReceiver : BroadcastReceiver() {
|
||||
@Suppress("DEPRECATION") // We do not retrieve the wallpaper but only listen to changes
|
||||
if (intent.action == Intent.ACTION_WALLPAPER_CHANGED) {
|
||||
flogDebug { "Wallpaper changed" }
|
||||
context.themeManager().value.updateActiveTheme()
|
||||
val themeManager by context.themeManager()
|
||||
themeManager.wallpaperChangedCounter.update { it + 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package dev.patrickgold.florisboard.lib
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisallowComposableCalls
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.SnapshotMutationPolicy
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.structuralEqualityPolicy
|
||||
@@ -28,21 +30,16 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceData
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceObserver
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@SuppressLint("StateFlowValueCalledInComposition")
|
||||
@Composable
|
||||
inline fun <V : Any, R : Any> PreferenceData<V>.observeAsTransformingState(
|
||||
policy: SnapshotMutationPolicy<R> = structuralEqualityPolicy(),
|
||||
crossinline transform: @DisallowComposableCalls (V) -> R,
|
||||
): State<R> {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val state = remember(key) { mutableStateOf(transform(get()), policy) }
|
||||
DisposableEffect(this, lifecycleOwner) {
|
||||
val observer = PreferenceObserver<V> { newValue -> state.value = transform(newValue) }
|
||||
observe(lifecycleOwner, observer)
|
||||
onDispose { removeObserver(observer) }
|
||||
return asFlow().let { flow ->
|
||||
flow.map { transform(it) }.collectAsState(transform(flow.value))
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -37,9 +37,9 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceLayout
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceUiContent
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
@@ -53,7 +53,7 @@ fun FlorisScreen(builder: @Composable FlorisScreenScope.() -> Unit) {
|
||||
|
||||
typealias FlorisScreenActions = @Composable RowScope.() -> Unit
|
||||
typealias FlorisScreenBottomBar = @Composable () -> Unit
|
||||
typealias FlorisScreenContent = PreferenceUiContent<AppPrefs>
|
||||
typealias FlorisScreenContent = PreferenceUiContent<FlorisPreferenceModel>
|
||||
typealias FlorisScreenFab = @Composable () -> Unit
|
||||
typealias FlorisScreenNavigationIcon = @Composable () -> Unit
|
||||
|
||||
@@ -152,7 +152,7 @@ private class FlorisScreenScopeImpl : FlorisScreenScope {
|
||||
Modifier
|
||||
}
|
||||
PreferenceLayout(
|
||||
florisPreferenceModel(),
|
||||
FlorisPreferenceStore,
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -56,6 +56,7 @@ import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import dev.patrickgold.florisboard.lib.util.InputMethodUtils
|
||||
import org.florisboard.lib.android.showShortToastSync
|
||||
|
||||
private const val AnimationDuration = 200
|
||||
|
||||
@@ -115,7 +116,7 @@ fun PreviewKeyboardField(
|
||||
Row {
|
||||
IconButton(onClick = {
|
||||
if (!InputMethodUtils.showImePicker(context)) {
|
||||
context.showShortToast("Error: InputMethodManager service not available!")
|
||||
context.showShortToastSync("Error: InputMethodManager service not available!")
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
|
||||
@@ -30,8 +30,8 @@ import android.widget.Toolbar
|
||||
import androidx.activity.ComponentActivity
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceStore
|
||||
import org.florisboard.lib.android.stringRes
|
||||
import dev.patrickgold.florisboard.lib.devtools.Devtools
|
||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||
@@ -39,14 +39,14 @@ import dev.patrickgold.florisboard.lib.devtools.flogWarning
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
private class SafePreferenceInstanceWrapper : ReadOnlyProperty<Any?, AppPrefs?> {
|
||||
private class SafePreferenceInstanceWrapper : ReadOnlyProperty<Any?, FlorisPreferenceModel?> {
|
||||
val cachedPreferenceModel = try {
|
||||
florisPreferenceModel()
|
||||
FlorisPreferenceStore
|
||||
} catch (_: Throwable) {
|
||||
null
|
||||
}
|
||||
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): AppPrefs? {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): FlorisPreferenceModel? {
|
||||
return cachedPreferenceModel?.getValue(thisRef, property)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import android.os.Build
|
||||
import android.os.Debug
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.lib.titlecase
|
||||
import dev.patrickgold.florisboard.lib.util.TimeUtils
|
||||
@@ -35,7 +35,7 @@ import java.io.InputStreamReader
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
object Devtools {
|
||||
fun generateDebugLog(context: Context, prefs: AppPrefs? = null, includeLogcat: Boolean = false): String {
|
||||
fun generateDebugLog(context: Context, prefs: FlorisPreferenceModel? = null, includeLogcat: Boolean = false): String {
|
||||
return buildString {
|
||||
append(generateDebugLogHeader(context, prefs))
|
||||
if (includeLogcat) {
|
||||
@@ -45,7 +45,7 @@ object Devtools {
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDebugLogHeader(context: Context, prefs: AppPrefs? = null): String {
|
||||
fun generateDebugLogHeader(context: Context, prefs: FlorisPreferenceModel? = null): String {
|
||||
return buildString {
|
||||
append(generateSystemInfoLog(context))
|
||||
appendLine()
|
||||
@@ -61,7 +61,7 @@ object Devtools {
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDebugLogForGithub(context: Context, prefs: AppPrefs? = null, includeLogcat: Boolean = false): String {
|
||||
fun generateDebugLogForGithub(context: Context, prefs: FlorisPreferenceModel? = null, includeLogcat: Boolean = false): String {
|
||||
return buildString {
|
||||
appendLine("<details>")
|
||||
appendLine("<summary>Detailed info (Debug log header)</summary>")
|
||||
@@ -113,7 +113,7 @@ object Devtools {
|
||||
}
|
||||
}
|
||||
|
||||
fun generateFeatureConfigLog(prefs: AppPrefs, withTitle: Boolean = true): String {
|
||||
fun generateFeatureConfigLog(prefs: FlorisPreferenceModel, withTitle: Boolean = true): String {
|
||||
return buildString {
|
||||
if (withTitle) appendLine("======= FEATURE CONFIG =======")
|
||||
append("Smartbar enabled : ").appendLine(prefs.smartbar.enabled.get())
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package dev.patrickgold.florisboard.lib.util
|
||||
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.FlorisPreferenceModel
|
||||
|
||||
object AppVersionUtils {
|
||||
private fun getRawVersionName(context: Context): String {
|
||||
@@ -28,7 +28,7 @@ object AppVersionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldShowChangelog(context: Context, prefs: AppPrefs): Boolean {
|
||||
fun shouldShowChangelog(context: Context, prefs: FlorisPreferenceModel): Boolean {
|
||||
val installVersion =
|
||||
VersionName.fromString(prefs.internal.versionOnInstall.get()) ?: VersionName.DEFAULT
|
||||
val lastChangelogVersion =
|
||||
@@ -39,14 +39,14 @@ object AppVersionUtils {
|
||||
return lastChangelogVersion < currentVersion && installVersion != currentVersion
|
||||
}
|
||||
|
||||
fun updateVersionOnInstallAndLastUse(context: Context, prefs: AppPrefs) {
|
||||
suspend fun updateVersionOnInstallAndLastUse(context: Context, prefs: FlorisPreferenceModel) {
|
||||
if (prefs.internal.versionOnInstall.get() == VersionName.DEFAULT_RAW) {
|
||||
prefs.internal.versionOnInstall.set(getRawVersionName(context))
|
||||
}
|
||||
prefs.internal.versionLastUse.set(getRawVersionName(context))
|
||||
}
|
||||
|
||||
fun updateVersionLastChangelog(context: Context, prefs: AppPrefs) {
|
||||
suspend fun updateVersionLastChangelog(context: Context, prefs: FlorisPreferenceModel) {
|
||||
prefs.internal.versionLastChangelog.set(getRawVersionName(context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[versions]
|
||||
# Main
|
||||
android-gradle-plugin = "8.9.3"
|
||||
android-gradle-plugin = "8.10.1"
|
||||
androidx-activity = "1.10.1"
|
||||
androidx-autofill = "1.1.0"
|
||||
androidx-collection = "1.5.0"
|
||||
@@ -11,16 +11,16 @@ androidx-emoji2 = "1.5.0"
|
||||
androidx-exifinterface = "1.4.1"
|
||||
androidx-navigation = "2.9.0"
|
||||
androidx-profileinstaller = "1.4.1"
|
||||
androidx-room = "2.6.1"
|
||||
androidx-room = "2.7.2"
|
||||
cache4k = "0.7.0"
|
||||
coil = "3.2.0"
|
||||
kotlin = "2.1.20"
|
||||
kotlin = "2.2.0"
|
||||
kotlinx-coroutines = "1.10.2"
|
||||
kotlinx-serialization-json = "1.8.1"
|
||||
ksp = "2.1.20-1.0.32"
|
||||
kotlinx-serialization-json = "1.9.0"
|
||||
ksp = "2.2.0-2.0.2"
|
||||
mikepenz-aboutlibraries = "12.1.2"
|
||||
patrickgold-compose-tooltip = "0.2.0-rc02"
|
||||
patrickgold-jetpref = "0.2.0-rc04"
|
||||
patrickgold-jetpref = "0.3.0-beta01"
|
||||
|
||||
# Testing
|
||||
androidx-benchmark = "1.3.4"
|
||||
@@ -63,6 +63,7 @@ mikepenz-aboutlibraries-core = { module = "com.mikepenz:aboutlibraries-core", ve
|
||||
mikepenz-aboutlibraries-compose = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "mikepenz-aboutlibraries" }
|
||||
patrickgold-compose-tooltip = { module = "dev.patrickgold.compose.tooltip:tooltip", version.ref = "patrickgold-compose-tooltip" }
|
||||
patrickgold-jetpref-datastore-model = { module = "dev.patrickgold.jetpref:jetpref-datastore-model", version.ref = "patrickgold-jetpref" }
|
||||
patrickgold-jetpref-datastore-model-processor = { module = "dev.patrickgold.jetpref:jetpref-datastore-model-processor", version.ref = "patrickgold-jetpref" }
|
||||
patrickgold-jetpref-datastore-ui = { module = "dev.patrickgold.jetpref:jetpref-datastore-ui", version.ref = "patrickgold-jetpref" }
|
||||
patrickgold-jetpref-material-ui = { module = "dev.patrickgold.jetpref:jetpref-material-ui", version.ref = "patrickgold-jetpref" }
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ package org.florisboard.lib.android
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.florisboard.lib.kotlin.CurlyArg
|
||||
|
||||
/**
|
||||
@@ -26,8 +29,8 @@ import org.florisboard.lib.kotlin.CurlyArg
|
||||
*
|
||||
* @param text The text to show in the toast popup.
|
||||
*/
|
||||
fun Context.showShortToast(text: String): Toast {
|
||||
return Toast.makeText(this, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
suspend fun Context.showShortToast(text: String): Toast = withContext(Dispatchers.Main.immediate) {
|
||||
Toast.makeText(this@showShortToast, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,9 +38,9 @@ fun Context.showShortToast(text: String): Toast {
|
||||
*
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
*/
|
||||
fun Context.showShortToast(@StringRes id: Int): Toast {
|
||||
suspend fun Context.showShortToast(@StringRes id: Int): Toast {
|
||||
val text = this.stringRes(id)
|
||||
return Toast.makeText(this, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
return showShortToast(text)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,9 +50,9 @@ fun Context.showShortToast(@StringRes id: Int): Toast {
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
* @param args The curly arguments which will be filled into the string template identified by [id].
|
||||
*/
|
||||
fun Context.showShortToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
suspend fun Context.showShortToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
val text = this.stringRes(id, *args)
|
||||
return Toast.makeText(this, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
return showShortToast(text)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +60,8 @@ fun Context.showShortToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
*
|
||||
* @param text The text to show in the toast popup.
|
||||
*/
|
||||
fun Context.showLongToast(text: String): Toast {
|
||||
return Toast.makeText(this, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
suspend fun Context.showLongToast(text: String): Toast = withContext(Dispatchers.Main.immediate) {
|
||||
Toast.makeText(this@showLongToast, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,9 +69,9 @@ fun Context.showLongToast(text: String): Toast {
|
||||
*
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
*/
|
||||
fun Context.showLongToast(@StringRes id: Int): Toast {
|
||||
suspend fun Context.showLongToast(@StringRes id: Int): Toast {
|
||||
val text = this.stringRes(id)
|
||||
return Toast.makeText(this, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
return showLongToast(text)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,7 +81,63 @@ fun Context.showLongToast(@StringRes id: Int): Toast {
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
* @param args The curly arguments which will be filled into the string template identified by [id].
|
||||
*/
|
||||
fun Context.showLongToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
suspend fun Context.showLongToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
val text = this.stringRes(id, *args)
|
||||
return Toast.makeText(this, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
return showLongToast(text)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// These wrappers are temporary, but needed.
|
||||
// Gradually in the future all event logic will be suspendable, then these wrappers will not be needed anymore.
|
||||
// DO NOT USE THESE IN SUSPENDABLE CONTEXTS, THIS CAUSES ISSUES
|
||||
|
||||
@Deprecated(
|
||||
"Use suspend showShortToast instead",
|
||||
ReplaceWith("showShortToast(text)")
|
||||
)
|
||||
fun Context.showShortToastSync(text: String): Toast = runBlocking {
|
||||
showShortToast(text)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use suspend showShortToast instead",
|
||||
ReplaceWith("showShortToast(id)")
|
||||
)
|
||||
fun Context.showShortToastSync(@StringRes id: Int): Toast = runBlocking {
|
||||
showShortToast(id)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use suspend showShortToast instead",
|
||||
ReplaceWith("showShortToast(id, *args)")
|
||||
)
|
||||
fun Context.showShortToastSync(@StringRes id: Int, vararg args: CurlyArg): Toast = runBlocking {
|
||||
showShortToast(id, *args)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use suspend showLongToast instead",
|
||||
ReplaceWith("showLongToast(text)")
|
||||
)
|
||||
fun Context.showLongToastSync(text: String): Toast = runBlocking {
|
||||
showLongToast(text)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use suspend showLongToast instead",
|
||||
ReplaceWith("showLongToast(id)")
|
||||
)
|
||||
fun Context.showLongToastSync(@StringRes id: Int): Toast = runBlocking {
|
||||
showLongToast(id)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use suspend showLongToast instead",
|
||||
ReplaceWith("showLongToast(id, *args)")
|
||||
)
|
||||
fun Context.showLongToastSync(@StringRes id: Int, vararg args: CurlyArg): Toast = runBlocking {
|
||||
showLongToast(id, *args)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,14 @@ package org.florisboard.lib.kotlin
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
fun <T> Flow<T>.collectIn(scope: CoroutineScope, collector: FlowCollector<T>) {
|
||||
scope.launch { this@collectIn.collect(collector) }
|
||||
scope.launch { collect(collector) }
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.collectLatestIn(scope: CoroutineScope, action: suspend (value: T) -> Unit) {
|
||||
scope.launch { this@collectLatestIn.collectLatest(action) }
|
||||
fun <T> StateFlow<T>.collectLatestIn(scope: CoroutineScope, action: suspend (value: T) -> Unit) {
|
||||
scope.launch { collectLatest(action) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user