Compare commits

..

3 Commits

Author SHA1 Message Date
Patrick Goldinger
f41385ae75 Adjust setup script 2024-10-20 18:46:48 +02:00
Patrick Goldinger
5c85be61d9 Add vscode env setup script 2024-10-20 18:46:41 +02:00
Patrick Goldinger
639beb9e64 Add initial flest implementation 2024-10-20 18:46:33 +02:00
354 changed files with 2212 additions and 2744 deletions

1
.gitignore vendored
View File

@@ -40,7 +40,6 @@ captures/
# Intellij
*.iml
.idea/
!/.idea/copyright/
# Keystore files
*.jks

View File

@@ -1,6 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (C) &amp;#36;originalComment.match(&quot;Copyright \(C\) (\d+)&quot;, 1, &quot;-&quot;, &quot;&amp;#36;today.year&quot;)&amp;#36;today.year The FlorisBoard Contributors&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="myName" value="copyright" />
</copyright>
</component>

View File

@@ -1,15 +0,0 @@
<component name="CopyrightManager">
<settings default="copyright">
<module2copyright>
<element module="Project Files" copyright="copyright" />
</module2copyright>
<LanguageOptions name="Shell Script">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="XML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
<LanguageOptions name="__TEMPLATE__" />
</settings>
</component>

View File

@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020-2025 The FlorisBoard Contributors
Copyright 2020 Patrick Goldinger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -114,7 +114,7 @@ Many thanks to [Nikolay Anzarov](https://www.behance.net/nikolayanzarov) ([@Bloo
## License
```
Copyright 2020-2025 The FlorisBoard Contributors
Copyright 2020-2024 Patrick Goldinger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -129,8 +129,6 @@ See the License for the specific language governing permissions and
limitations under the License.
```
Thanks to [The FlorisBoard Contributors](https://github.com/florisboard/florisboard/graphs/contributors) for making this project possible!
<!-- BEGIN SECTION: obtainium_links -->
<!-- auto-generated link templates, do NOT edit by hand -->
<!-- see fastlane/update-readme.sh -->

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "145ca5bf4bff8e98f71ebc70ab3b495b",
"identityHash": "282a1b421e498fd0e21c055b6a4315e0",
"entities": [
{
"tableName": "clipboard_history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `text` TEXT, `uri` TEXT, `creationTimestampMs` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `mimeTypes` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL DEFAULT 0, `isRemoteDevice` INTEGER NOT NULL DEFAULT 0)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `text` TEXT, `uri` TEXT, `creationTimestampMs` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `mimeTypes` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `isRemoteDevice` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
@@ -54,15 +54,13 @@
"fieldPath": "isSensitive",
"columnName": "isSensitive",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
"notNull": true
},
{
"fieldPath": "isRemoteDevice",
"columnName": "isRemoteDevice",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
"notNull": true
}
],
"primaryKey": {
@@ -88,7 +86,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '145ca5bf4bff8e98f71ebc70ab3b495b')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '282a1b421e498fd0e21c055b6a4315e0')"
]
}
}

View File

@@ -1,94 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "1dd181d116dcb4530fb5b33451ea9ab5",
"entities": [
{
"tableName": "clipboard_history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `text` TEXT, `uri` TEXT, `creationTimestampMs` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `mimeTypes` TEXT NOT NULL, `is_sensitive` INTEGER NOT NULL DEFAULT 0, `is_remote_device` INTEGER NOT NULL DEFAULT 0)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "text",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uri",
"columnName": "uri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "creationTimestampMs",
"columnName": "creationTimestampMs",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isPinned",
"columnName": "isPinned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mimeTypes",
"columnName": "mimeTypes",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isSensitive",
"columnName": "is_sensitive",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "isRemoteDevice",
"columnName": "is_remote_device",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"_id"
]
},
"indices": [
{
"name": "index_clipboard_history__id",
"unique": false,
"columnNames": [
"_id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_clipboard_history__id` ON `${TABLE_NAME}` (`_id`)"
}
],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1dd181d116dcb4530fb5b33451ea9ab5')"
]
}
}

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard
import androidx.test.ext.junit.runners.AndroidJUnit4

View File

@@ -1,4 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020-2022 Patrick Goldinger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

View File

@@ -72,7 +72,7 @@
"র": {
"main": { "$": "auto_text_key", "code": 2482, "label": "ল" },
"relevant": [
{ "code": -255, "label": "র্য" }
{ "code": -255, "label": "র্য" }
]
},
"ন": {

View File

@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020-2025 The FlorisBoard Contributors
Copyright 2020 Patrick Goldinger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,6 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material3.ButtonDefaults
import androidx.compose.runtime.Composable
@@ -107,6 +106,13 @@ import dev.patrickgold.florisboard.lib.devtools.flogError
import dev.patrickgold.florisboard.lib.devtools.flogInfo
import dev.patrickgold.florisboard.lib.devtools.flogWarning
import dev.patrickgold.florisboard.lib.observeAsTransformingState
import org.florisboard.lib.snygg.ui.SnyggSurface
import org.florisboard.lib.snygg.ui.shape
import org.florisboard.lib.snygg.ui.snyggBackground
import org.florisboard.lib.snygg.ui.snyggBorder
import org.florisboard.lib.snygg.ui.snyggShadow
import org.florisboard.lib.snygg.ui.solidColor
import org.florisboard.lib.snygg.ui.spSize
import dev.patrickgold.florisboard.lib.util.ViewUtils
import dev.patrickgold.florisboard.lib.util.debugSummarize
import dev.patrickgold.florisboard.lib.util.launchActivity
@@ -118,13 +124,6 @@ import org.florisboard.lib.android.isOrientationPortrait
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.systemServiceOrNull
import org.florisboard.lib.kotlin.collectLatestIn
import org.florisboard.lib.snygg.ui.SnyggSurface
import org.florisboard.lib.snygg.ui.shape
import org.florisboard.lib.snygg.ui.snyggBackground
import org.florisboard.lib.snygg.ui.snyggBorder
import org.florisboard.lib.snygg.ui.snyggShadow
import org.florisboard.lib.snygg.ui.solidColor
import org.florisboard.lib.snygg.ui.spSize
import java.lang.ref.WeakReference
/**
@@ -552,7 +551,7 @@ class FlorisImeService : LifecycleInputMethodService() {
.fillMaxWidth()
.weight(1f),
) {
DevtoolsOverlay(modifier = Modifier.fillMaxSize())
DevtoolsUi()
}
}
ImeUi()
@@ -598,7 +597,6 @@ class FlorisImeService : LifecycleInputMethodService() {
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.safeDrawingPadding()
// FIXME: removing this fixes the Smartbar sizing but breaks one-handed-mode
//.height(IntrinsicSize.Min)
.padding(bottom = bottomOffset),
@@ -639,6 +637,14 @@ class FlorisImeService : LifecycleInputMethodService() {
}
}
@Composable
private fun DevtoolsUi() {
val devtoolsEnabled by prefs.devtools.enabled.observeAsState()
if (devtoolsEnabled) {
DevtoolsOverlay(modifier = Modifier.fillMaxSize())
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =
if (keyboardManager.onHardwareKeyDown(keyCode, event)) true
else super.onKeyDown(keyCode, event)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021-2024 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,8 +47,10 @@ import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.ime.theme.ThemeMode
import dev.patrickgold.florisboard.ime.theme.extCoreTheme
import org.florisboard.lib.android.isOrientationPortrait
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
import dev.patrickgold.florisboard.lib.observeAsTransformingState
import org.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.util.VersionName
import dev.patrickgold.jetpref.datastore.JetPref
import dev.patrickgold.jetpref.datastore.model.PreferenceMigrationEntry
@@ -57,8 +59,6 @@ import dev.patrickgold.jetpref.datastore.model.PreferenceType
import dev.patrickgold.jetpref.datastore.model.observeAsState
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.florisboard.lib.android.isOrientationPortrait
import org.florisboard.lib.snygg.SnyggLevel
fun florisPreferenceModel() = JetPref.getOrCreatePreferenceModel(AppPrefs::class, ::AppPrefs)
@@ -118,14 +118,6 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "clipboard__clean_up_after",
default = 20,
)
val autoCleanSensitive = boolean(
key = "clipboard__auto_clean_sensitive",
default = false,
)
val autoCleanSensitiveAfter = int(
key = "clipboard__auto_clean_sensitive_after",
default = 20,
)
val limitHistorySize = boolean(
key = "clipboard__limit_history_size",
default = true,
@@ -166,8 +158,8 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "devtools__enabled",
default = false,
)
val showLastLayoutComputation = boolean(
key = "devtools__show_last_layout_computation",
val showHeapMemoryStats = boolean(
key = "devtools__show_heap_memory_stats",
default = false,
)
val showPrimaryClip = boolean(

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app
import androidx.compose.runtime.Composable

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,9 +42,7 @@ import androidx.compose.ui.unit.sp
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.editorInstance
import dev.patrickgold.florisboard.ime.keyboard.CachedLayout
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.FlorisLocale
import dev.patrickgold.florisboard.lib.observeAsNonNullState
import dev.patrickgold.florisboard.nlpManager
@@ -58,37 +56,28 @@ 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 keyboardManager by context.keyboardManager()
val devtoolsEnabled by prefs.devtools.enabled.observeAsState()
val showPrimaryClip by prefs.devtools.showPrimaryClip.observeAsState()
val showInputStateOverlay by prefs.devtools.showInputStateOverlay.observeAsState()
val showLastLayoutComputation by prefs.devtools.showLastLayoutComputation.observeAsState()
val showSpellingOverlay by prefs.devtools.showSpellingOverlay.observeAsState()
val showInlineAutofillOverlay by prefs.devtools.showInlineAutofillOverlay.observeAsState()
val debugLayoutResult by keyboardManager.layoutManager.debugLayoutComputationResultFlow.collectAsState()
CompositionLocalProvider(
LocalContentColor provides Color.White,
LocalLayoutDirection provides LayoutDirection.Ltr,
) {
Column(modifier = modifier) {
if (devtoolsEnabled && showPrimaryClip) {
if (showPrimaryClip) {
DevtoolsClipboardOverlay()
}
if (devtoolsEnabled && showInputStateOverlay) {
if (showInputStateOverlay) {
DevtoolsInputStateOverlay()
}
if (devtoolsEnabled && showLastLayoutComputation || debugLayoutResult?.allLayoutsSuccess() == false) {
DevtoolsLastLayoutComputationOverlay()
}
if (devtoolsEnabled && showSpellingOverlay) {
if (showSpellingOverlay) {
DevtoolsSpellingOverlay()
}
if (devtoolsEnabled && showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
if (showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
DevtoolsInlineAutofillOverlay()
}
}
@@ -136,38 +125,6 @@ private fun DevtoolsInputStateOverlay() {
}
}
@Composable
private fun DevtoolsLastLayoutComputationOverlay() {
val context = LocalContext.current
val keyboardManager by context.keyboardManager()
val debugLayoutResult by keyboardManager.layoutManager.debugLayoutComputationResultFlow.collectAsState()
@Composable
fun PrintResult(result: Result<CachedLayout>) {
if (result.isSuccess) {
DevtoolsText(text = "loaded: ${result.getOrNull()?.name}")
} else {
DevtoolsText(text = "error: ${result.exceptionOrNull()}")
}
}
DevtoolsOverlayBox(title = "Last layout computation") {
if (debugLayoutResult == null) {
DevtoolsText(text = "No layout computation result available.")
return@DevtoolsOverlayBox
}
DevtoolsSubGroup(title = "main") {
PrintResult(debugLayoutResult!!.main)
}
DevtoolsSubGroup(title = "mod") {
PrintResult(debugLayoutResult!!.mod)
}
DevtoolsSubGroup(title = "ext") {
PrintResult(debugLayoutResult!!.ext)
}
}
}
@Composable
private fun DevtoolsSpellingOverlay() {
val context = LocalContext.current

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,6 +61,12 @@ fun DevtoolsScreen() = FlorisScreen {
)
PreferenceGroup(title = stringRes(R.string.devtools__title)) {
SwitchPreference(
prefs.devtools.showHeapMemoryStats,
title = stringRes(R.string.devtools__show_heap_memory_stats__label),
summary = stringRes(R.string.devtools__show_heap_memory_stats__summary),
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
SwitchPreference(
prefs.devtools.showPrimaryClip,
title = stringRes(R.string.devtools__show_primary_clip__label),
@@ -73,12 +79,6 @@ fun DevtoolsScreen() = FlorisScreen {
summary = stringRes(R.string.devtools__show_input_state_overlay__summary),
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
SwitchPreference(
prefs.devtools.showLastLayoutComputation,
title = "Show last layout computation",
summary = "Show the last layout computation in a dialog",
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
SwitchPreference(
prefs.devtools.showSpellingOverlay,
title = stringRes(R.string.devtools__show_spelling_overlay__label),

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Row

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.ext
import androidx.compose.runtime.Composable

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Row

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024-2025 The FlorisBoard Contributors
* Copyright (C) 2024 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,15 +17,10 @@
package dev.patrickgold.florisboard.app.ext
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Edit
@@ -38,13 +33,8 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import dev.patrickgold.florisboard.R
@@ -56,7 +46,6 @@ import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
import dev.patrickgold.florisboard.lib.observeAsNonNullState
@@ -91,66 +80,49 @@ enum class ExtensionListScreenType(
fun ExtensionListScreen(type: ExtensionListScreenType, showUpdate: Boolean) = FlorisScreen {
title = stringRes(type.titleResId)
previewFieldVisible = false
scrollable = false
val context = LocalContext.current
val navController = LocalNavController.current
val extensionManager by context.extensionManager()
val extensionIndex by type.getExtensionIndex(extensionManager).observeAsNonNullState()
var fabHeight by remember {
mutableStateOf(0)
}
val fabHeightDp = with(LocalDensity.current) { fabHeight.toDp()+16.dp }
val listState = rememberLazyListState()
content {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.florisScrollbar(state = listState, isVertical = true),
state = listState,
contentPadding = PaddingValues(bottom = fabHeightDp),
) {
if (showUpdate) {
item {
UpdateBox(extensionIndex = extensionIndex)
}
}
items(extensionIndex) { ext ->
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
title = ext.meta.title,
subtitle = ext.meta.id,
if (showUpdate) {
UpdateBox(extensionIndex = extensionIndex)
}
for (ext in extensionIndex) {
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
title = ext.meta.title,
subtitle = ext.meta.id,
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
text = ext.meta.description ?: "",
style = MaterialTheme.typography.bodySmall,
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
text = ext.meta.description ?: "",
style = MaterialTheme.typography.bodySmall,
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.View(ext.meta.id))
},
icon = Icons.Outlined.Info,
text = stringRes(id = R.string.ext__list__view_details),//stringRes(R.string.action__add),
colors = ButtonDefaults.textButtonColors(),
)
Spacer(modifier = Modifier.weight(1f))
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.Edit(ext.meta.id))
},
icon = Icons.Default.Edit,
text = stringRes(R.string.action__edit),
enabled = extensionManager.canDelete(ext),
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.View(ext.meta.id))
},
icon = Icons.Outlined.Info,
text = stringRes(id = R.string.ext__list__view_details),//stringRes(R.string.action__add),
colors = ButtonDefaults.textButtonColors(),
)
Spacer(modifier = Modifier.weight(1f))
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.Edit(ext.meta.id))
},
icon = Icons.Default.Edit,
text = stringRes(R.string.action__edit),
enabled = extensionManager.canDelete(ext),
)
}
}
}
}
@@ -170,9 +142,6 @@ fun ExtensionListScreen(type: ExtensionListScreenType, showUpdate: Boolean) = Fl
text = stringRes(id = R.string.ext__editor__title_create_any),
)
},
modifier = Modifier.onGloballyPositioned {
fabHeight = it.size.height
},
shape = FloatingActionButtonDefaults.extendedFabShape,
onClick = { type.launchExtensionCreate.invoke(navController) },
)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
import org.florisboard.lib.android.AndroidVersion
@OptIn(ExperimentalJetPrefDatastoreUi::class)
@Composable
@@ -72,22 +71,6 @@ fun ClipboardScreen() = FlorisScreen {
stepIncrement = 5,
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true && prefs.clipboard.cleanUpOld isEqualTo true },
)
SwitchPreference(
prefs.clipboard.autoCleanSensitive,
title = stringRes(R.string.pref__clipboard__auto_clean_sensitive__label),
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true },
visibleIf = { AndroidVersion.ATLEAST_API33_T },
)
DialogSliderPreference(
prefs.clipboard.autoCleanSensitiveAfter,
title = stringRes(R.string.pref__clipboard__auto_clean_sensitive_after__label),
valueLabel = { pluralsRes(R.plurals.unit__seconds__written, it, "v" to it) },
min = 0,
max = 300,
stepIncrement = 10,
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true && prefs.clipboard.autoCleanSensitive isEqualTo true },
visibleIf = { AndroidVersion.ATLEAST_API33_T },
)
SwitchPreference(
prefs.clipboard.limitHistorySize,
title = stringRes(R.string.pref__clipboard__limit_history_size__label),

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,17 +25,12 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -78,7 +73,6 @@ import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownLikeButton
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownMenu
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
import dev.patrickgold.florisboard.lib.observeAsNonNullState
@@ -184,7 +178,7 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
})
val selectValue = stringRes(R.string.settings__localization__subtype_select_placeholder)
val selectListValues = remember(selectValue) { listOf(selectValue) }
val selectListValues = remember (selectValue) { listOf(selectValue) }
val prefs by florisPreferenceModel()
val navController = LocalNavController.current
@@ -235,7 +229,7 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
@Composable
fun SubtypePropertyDropdown(
title: String,
layoutType: LayoutType,
layoutType: LayoutType
) {
SubtypeProperty(title) {
SubtypeLayoutDropdown(
@@ -333,7 +327,6 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
DisplayLanguageNamesIn.NATIVE_LOCALE -> suggestedPreset.locale.displayName(suggestedPreset.locale)
},
secondaryText = suggestedPreset.preferred.characters.componentId,
colors = ListItemDefaults.colors(containerColor = CardDefaults.cardColors().containerColor),
)
}
} else {
@@ -488,30 +481,20 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
showSubtypePresetsDialog = false
},
) {
Column {
HorizontalDivider()
val lazyListState = rememberLazyListState()
LazyColumn(
modifier = Modifier
.florisScrollbar(lazyListState, isVertical = true).weight(1f),
state = lazyListState,
) {
items(subtypePresets) { subtypePreset ->
JetPrefListItem(
modifier = Modifier.clickable {
subtypeEditor.applySubtype(subtypePreset.toSubtype())
showSubtypePresetsDialog = false
},
text = when (displayLanguageNamesIn) {
DisplayLanguageNamesIn.SYSTEM_LOCALE -> subtypePreset.locale.displayName()
DisplayLanguageNamesIn.NATIVE_LOCALE -> subtypePreset.locale.displayName(subtypePreset.locale)
},
secondaryText = subtypePreset.preferred.characters.componentId,
colors = ListItemDefaults.colors(containerColor = AlertDialogDefaults.containerColor),
)
}
LazyColumn {
items(subtypePresets) { subtypePreset ->
JetPrefListItem(
modifier = Modifier.clickable {
subtypeEditor.applySubtype(subtypePreset.toSubtype())
showSubtypePresetsDialog = false
},
text = when (displayLanguageNamesIn) {
DisplayLanguageNamesIn.SYSTEM_LOCALE -> subtypePreset.locale.displayName()
DisplayLanguageNamesIn.NATIVE_LOCALE -> subtypePreset.locale.displayName(subtypePreset.locale)
},
secondaryText = subtypePreset.preferred.characters.componentId,
)
}
HorizontalDivider()
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024-2025 The FlorisBoard Contributors
* Copyright (C) 2024 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,18 +19,10 @@ package dev.patrickgold.florisboard.app.settings.media
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.EmojiSymbols
import androidx.compose.material.icons.outlined.Schedule
import androidx.compose.material3.Text
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.runtime.setValue
import dev.patrickgold.florisboard.R
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
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSuggestionType
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -39,11 +31,8 @@ import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import kotlinx.coroutines.launch
@OptIn(ExperimentalJetPrefDatastoreUi::class)
@Composable
@@ -52,11 +41,6 @@ fun MediaScreen() = FlorisScreen {
previewFieldVisible = true
iconSpaceReserved = true
val prefs by florisPreferenceModel()
var shouldDelete by remember { mutableStateOf<ShouldDelete?>(null) }
val scope = rememberCoroutineScope()
content {
ListPreference(
prefs.emoji.preferredSkinTone,
@@ -101,21 +85,6 @@ fun MediaScreen() = FlorisScreen {
stepIncrement = 1,
enabledIf = { prefs.emoji.historyEnabled.isTrue() },
)
Preference(
title = stringRes(R.string.prefs__media__emoji_history_pinned_reset),
onClick = {
shouldDelete = ShouldDelete(true)
},
enabledIf = { prefs.emoji.historyEnabled.isTrue() },
)
Preference(
title = stringRes(R.string.prefs__media__emoji_history_reset),
onClick = {
shouldDelete = ShouldDelete(false)
},
enabledIf = { prefs.emoji.historyEnabled.isTrue() },
)
}
PreferenceGroup(title = stringRes(R.string.prefs__media__emoji_suggestion__title)) {
@@ -169,49 +138,4 @@ fun MediaScreen() = FlorisScreen {
)
}
}
DeleteEmojiHistoryConfirmDialog(
shouldDelete = shouldDelete,
onDismiss = {
shouldDelete = null
},
onConfirm = {
shouldDelete?.let {
scope.launch {
if (it.pinned) {
EmojiHistoryHelper.deletePinned(prefs = prefs)
} else {
EmojiHistoryHelper.deleteHistory(prefs = prefs)
}
}
shouldDelete = null
}
},
)
}
@Composable
fun DeleteEmojiHistoryConfirmDialog(
shouldDelete: ShouldDelete?,
onDismiss: () -> Unit,
onConfirm: () -> Unit,
) {
shouldDelete?.let {
JetPrefAlertDialog(
title = stringRes(R.string.action__reset_confirm_title),
confirmLabel = stringRes(R.string.action__yes),
dismissLabel = stringRes(R.string.action__no),
onDismiss = onDismiss,
onConfirm = onConfirm,
) {
if (it.pinned) {
Text(stringRes(R.string.action__reset_confirm_message, "name" to "pinned emojis"))
} else {
Text(stringRes(R.string.action__reset_confirm_message, "name" to "emoji history"))
}
}
}
}
data class ShouldDelete(val pinned: Boolean)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@ import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
import org.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.compose.FlorisErrorCard
import dev.patrickgold.florisboard.lib.compose.FlorisHyperlinkText
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -47,7 +48,6 @@ import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
import org.florisboard.lib.android.AndroidVersion
@OptIn(ExperimentalJetPrefDatastoreUi::class)
@Composable
@@ -58,11 +58,11 @@ fun TypingScreen() = FlorisScreen {
val navController = LocalNavController.current
content {
// This card is temporary and is therefore not using a string resource (not so temporary as we thought...)
// This card is temporary and is therefore not using a string resource
FlorisErrorCard(
modifier = Modifier.padding(8.dp),
text = """
Suggestions (except system autofill) and spell checking are not available in this release. All
Suggestions (except system autofill) and spell checking are not available in this alpha release. All
preferences in the "Corrections" group are properly implemented though.
""".trimIndent().replace('\n', ' '),
)

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.setup
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -254,20 +254,14 @@ class ClipboardManager(
}
private fun enforceExpiryDate(clipHistory: ClipboardHistory) {
val itemsToRemove = mutableSetOf<ClipboardItem>()
if (prefs.clipboard.cleanUpOld.get()) {
val nonPinnedItems = clipHistory.recent + clipHistory.other
val expiryTime = System.currentTimeMillis() - (prefs.clipboard.cleanUpAfter.get() * 60 * 1000)
itemsToRemove.addAll(nonPinnedItems.filter { it.creationTimestampMs < expiryTime })
}
if (prefs.clipboard.autoCleanSensitive.get()) {
val sensitiveData = clipHistory.all.filter { it.isSensitive }
val expiryTime = System.currentTimeMillis() - (prefs.clipboard.autoCleanSensitiveAfter.get() * 1000)
itemsToRemove.addAll(sensitiveData.filter { it.creationTimestampMs < expiryTime })
}
if (itemsToRemove.isNotEmpty()) {
ioScope.launch {
clipHistoryDao?.delete(itemsToRemove.toList())
val itemsToRemove = nonPinnedItems.filter { it.creationTimestampMs < expiryTime }
if (itemsToRemove.isNotEmpty()) {
ioScope.launch {
clipHistoryDao?.delete(itemsToRemove)
}
}
}
}

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.clipboard
import android.content.ClipData

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.core.database.getStringOrNull
import androidx.lifecycle.LiveData
import androidx.room.AutoMigration
import androidx.room.ColumnInfo
import androidx.room.Dao
import androidx.room.Database
@@ -39,13 +38,11 @@ import androidx.room.Entity
import androidx.room.Insert
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.RenameColumn
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import androidx.room.Update
import androidx.room.migration.AutoMigrationSpec
import dev.patrickgold.florisboard.R
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.ExperimentalSerializationApi
@@ -91,10 +88,8 @@ data class ClipboardItem @OptIn(ExperimentalSerializationApi::class) constructor
val isPinned: Boolean,
val mimeTypes: Array<String>,
@EncodeDefault
@ColumnInfo(name = "is_sensitive", defaultValue = "0")
val isSensitive: Boolean = false,
@EncodeDefault
@ColumnInfo(name= "is_remote_device", defaultValue = "0")
val isRemoteDevice: Boolean = false,
) {
companion object {
@@ -242,7 +237,6 @@ data class ClipboardItem @OptIn(ExperimentalSerializationApi::class) constructor
if (uri != other.uri) return false
if (creationTimestampMs != other.creationTimestampMs) return false
if (!mimeTypes.contentEquals(other.mimeTypes)) return false
if (isSensitive != other.isSensitive) return false
return true
}
@@ -254,7 +248,6 @@ data class ClipboardItem @OptIn(ExperimentalSerializationApi::class) constructor
result = 31 * result + (uri?.hashCode() ?: 0)
result = 31 * result + creationTimestampMs.hashCode()
result = 31 * result + mimeTypes.contentHashCode()
result = 31 * result + isSensitive.hashCode()
return result
}
@@ -339,30 +332,11 @@ interface ClipboardHistoryDao {
fun deleteAllUnpinned()
}
@Database(
entities = [ClipboardItem::class],
version = 4,
autoMigrations = [
AutoMigration(from = 2, to = 4),
AutoMigration(from = 3, to = 4, spec = ClipboardHistoryDatabase.MIGRATE_3_TO_4::class),
],
)
@Database(entities = [ClipboardItem::class], version = 3)
@TypeConverters(Converters::class)
abstract class ClipboardHistoryDatabase : RoomDatabase() {
abstract fun clipboardItemDao(): ClipboardHistoryDao
@RenameColumn(
tableName = CLIPBOARD_HISTORY_TABLE,
fromColumnName = "isSensitive",
toColumnName = "is_sensitive",
)
@RenameColumn(
tableName = CLIPBOARD_HISTORY_TABLE,
fromColumnName = "isRemoteDevice",
toColumnName = "is_remote_device",
)
class MIGRATE_3_TO_4 : AutoMigrationSpec
companion object {
fun new(context: Context): ClipboardHistoryDatabase {
return Room

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -634,7 +634,7 @@ abstract class AbstractEditorInstance(context: Context) {
suspend fun popUntilOrNull(predicate: (EditorContent) -> Boolean): EditorContent? {
return list.withLock { list ->
while (list.isNotEmpty()) {
val item = list.removeAt(0)
val item = list.removeFirst()
if (predicate(item)) return@withLock item
}
return@withLock null

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,19 +1,3 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.input
enum class CapitalizationBehavior {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2025 The FlorisBoard Contributors
* Copyright (C) 2022 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2025 The FlorisBoard Contributors
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

Some files were not shown because too many files have changed in this diff Show More