Compare commits
146 Commits
v0.3.15-be
...
v0.3.16-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4adaf9a315 | ||
|
|
01eee827df | ||
|
|
fd87241887 | ||
|
|
d63792cb15 | ||
|
|
e2c4992b51 | ||
|
|
481d929f2b | ||
|
|
3d1f1d1e12 | ||
|
|
9f4ef7e1ad | ||
|
|
7d24f0c5ae | ||
|
|
67408130b1 | ||
|
|
cdb9504e5f | ||
|
|
977b32de6e | ||
|
|
4ae4eb00e9 | ||
|
|
063fca6dd1 | ||
|
|
a650bfe94c | ||
|
|
517448da06 | ||
|
|
8ba9abdace | ||
|
|
193d03e0eb | ||
|
|
363cfe1443 | ||
|
|
d9cd36966e | ||
|
|
02bfae55b9 | ||
|
|
6edbf64104 | ||
|
|
1c29319036 | ||
|
|
8c8664cafa | ||
|
|
652c7f4e4b | ||
|
|
753fbc30df | ||
|
|
01de9a4ae1 | ||
|
|
aa52784174 | ||
|
|
dc72e2162e | ||
|
|
8ef37cedfb | ||
|
|
08a77ce0eb | ||
|
|
afc6f21a6a | ||
|
|
bdc2a9a5d3 | ||
|
|
c27365bccd | ||
|
|
83d4fc727d | ||
|
|
5bf4819d83 | ||
|
|
60221743f6 | ||
|
|
9d78661ecb | ||
|
|
addedb6f9b | ||
|
|
e1701b2ba7 | ||
|
|
380a0e4f4c | ||
|
|
7fb24c0471 | ||
|
|
aaae483ad8 | ||
|
|
578652b9ba | ||
|
|
b8133b17fe | ||
|
|
8226a4fcb9 | ||
|
|
ea85a63da9 | ||
|
|
21e784fb09 | ||
|
|
0a1fb5a51e | ||
|
|
2a3c3e07e2 | ||
|
|
f8eb86806e | ||
|
|
25a7c47c3c | ||
|
|
f08d92fef4 | ||
|
|
362a84de51 | ||
|
|
64fefef31a | ||
|
|
b0fced6f98 | ||
|
|
406f79ee36 | ||
|
|
893fc758b1 | ||
|
|
126de62f80 | ||
|
|
0ee634a83d | ||
|
|
d4f634e8af | ||
|
|
f544e1203d | ||
|
|
d0a373f5f4 | ||
|
|
e4dfed3940 | ||
|
|
7f674f89d2 | ||
|
|
0d593a07e6 | ||
|
|
261c8fbec1 | ||
|
|
d5262e3ad2 | ||
|
|
527543331a | ||
|
|
75623f2a95 | ||
|
|
29f6658256 | ||
|
|
dbc6606237 | ||
|
|
1108456a8e | ||
|
|
2debf36cb6 | ||
|
|
896101b840 | ||
|
|
a84854a5b1 | ||
|
|
461966de96 | ||
|
|
6dd3713641 | ||
|
|
d51b301364 | ||
|
|
f8db5d3881 | ||
|
|
781a00e7c2 | ||
|
|
a1bb73ba9d | ||
|
|
d6390108c2 | ||
|
|
fee954c95f | ||
|
|
0347eabc04 | ||
|
|
c6bcd8a89c | ||
|
|
114bcb0d4b | ||
|
|
f4a1a04997 | ||
|
|
70a859e00b | ||
|
|
8d3b2ef474 | ||
|
|
76efc0a0e0 | ||
|
|
166734757f | ||
|
|
97f401371f | ||
|
|
b012e5377b | ||
|
|
3b18dc33d8 | ||
|
|
d798f01576 | ||
|
|
55281bd7d6 | ||
|
|
88e9bde0a9 | ||
|
|
54d5a16761 | ||
|
|
701da50479 | ||
|
|
b43b6aa2d0 | ||
|
|
4279e9d100 | ||
|
|
e5bd979880 | ||
|
|
9a48169bf3 | ||
|
|
99cfd99815 | ||
|
|
e8f082d885 | ||
|
|
b63f475a8c | ||
|
|
e183f10969 | ||
|
|
c1e624b9a0 | ||
|
|
2d87d0e4d3 | ||
|
|
bcf1bffc24 | ||
|
|
f388e8811e | ||
|
|
7ededa6293 | ||
|
|
7d9e1cf2b5 | ||
|
|
299f581609 | ||
|
|
c38d4ed90b | ||
|
|
647bc659d7 | ||
|
|
61eb09e611 | ||
|
|
1a4118d29a | ||
|
|
48655b3771 | ||
|
|
17649c44bf | ||
|
|
7cbb19ddcb | ||
|
|
e13ac7c689 | ||
|
|
941733cdc0 | ||
|
|
a25289a856 | ||
|
|
7bcfeca872 | ||
|
|
240ebc499a | ||
|
|
831882f419 | ||
|
|
e0e5259b4c | ||
|
|
33cd2b5d01 | ||
|
|
d3dda86966 | ||
|
|
59aa5cdb33 | ||
|
|
d26e820492 | ||
|
|
b8b1b04c7e | ||
|
|
26b4acc894 | ||
|
|
12c4220544 | ||
|
|
5fc4f5ba60 | ||
|
|
03ea9bcb76 | ||
|
|
a04c44df98 | ||
|
|
b1431c7e51 | ||
|
|
c09719ffd6 | ||
|
|
16149d95a1 | ||
|
|
658e43da9c | ||
|
|
66ddb451ab | ||
|
|
f135513f3e | ||
|
|
322dfa717b |
BIN
.github/repo_icon.png
vendored
Normal file
|
After Width: | Height: | Size: 55 KiB |
8
.github/workflows/android.yml
vendored
@@ -29,14 +29,6 @@ jobs:
|
||||
java-version: 11
|
||||
- name: Setup CMake and Ninja
|
||||
uses: lukka/get-cmake@v3.20.1
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Build with Gradle
|
||||
# MUST call gradlew separately because of an OSS license plugin issue.
|
||||
# See https://github.com/google/play-services-plugins/issues/199
|
||||
|
||||
3
.gitignore
vendored
@@ -43,6 +43,3 @@ crowdin.properties
|
||||
|
||||
# C++
|
||||
.cxx/
|
||||
|
||||
# AndroidX Room schema JSONs
|
||||
/app/schemas/
|
||||
|
||||
@@ -64,7 +64,7 @@ For the `code` field of each key, make sure to use the UTF-8 code. An useful too
|
||||
is [unicode-table.com](https://unicode-table.com/en/). From there, you search for your letter and then use the HTML
|
||||
code, but without the `&#;`
|
||||
For internal codes of functional or UI keys, see
|
||||
[`app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt`](app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt)
|
||||
[`app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt`](app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/key/KeyCode.kt)
|
||||
.
|
||||
|
||||
The label is equally important and should always match up with the defined code. If `code` and `label` don't match up,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<img align="left" width="80" height="80"
|
||||
src="fastlane/metadata/android/en-US/images/icon.png" alt="App icon">
|
||||
src=".github/repo_icon.png" alt="App icon">
|
||||
|
||||
# FlorisBoard [](https://crowdin.florisboard.patrickgold.dev) [](https://matrix.to/#/#florisboard:matrix.org) 
|
||||
|
||||
**FlorisBoard** is a free and open-source keyboard for Android 6.0+
|
||||
**FlorisBoard** is a free and open-source keyboard for Android 7.0+
|
||||
devices. It aims at being modern, user-friendly and customizable while
|
||||
fully respecting your privacy. Currently in early-beta state.
|
||||
|
||||
@@ -97,6 +97,8 @@ to get more information on this topic.
|
||||
* [Nuspell](https://github.com/nuspell/nuspell) by
|
||||
[Nuspell](https://github.com/nuspell)
|
||||
|
||||
Many thanks to [Nikolay Anzarov](https://www.behance.net/nikolayanzarov) ([@BloodRaven0](https://github.com/BloodRaven0)) for designing and providing the main app icons to this project!
|
||||
|
||||
## License
|
||||
```
|
||||
Copyright 2020-2022 Patrick Goldinger
|
||||
|
||||
48
ROADMAP.md
@@ -1,3 +1,4 @@
|
||||
|
||||
# FlorisBoard's feature roadmap & milestones
|
||||
|
||||
This feature roadmap intents to provide transparency to what I want to add to FlorisBoard in the foreseeable future.
|
||||
@@ -14,42 +15,13 @@ Releases in this section still follow the old versioning scheme, meaning the pat
|
||||
naming convention is more confusing than useful, beginning with v0.4.0 development a new release/development cycle will
|
||||
be introduced.
|
||||
|
||||
### 0.3.14 (almost completed, release candidate phase)
|
||||
### 0.3.15 & 0.3.16 (currently 0.3.15 done, 0.3.16 in work)
|
||||
|
||||
- Re-write of the Preference core
|
||||
- Reduce redundancy in key/default value definitions
|
||||
- Avoid having to manually add redundant code for adding a new pref
|
||||
- Goes hand-in-hand with the Settings UI re-write
|
||||
- Re-write of the Settings UI with Jetpack Compose
|
||||
- Also re-structure UI into a more list-like panel
|
||||
- Adjust theme colors of Settings a bit to make it more modern
|
||||
- Preview the keyboard at any time from within the Settings
|
||||
- Settings language different than device language
|
||||
- Re-write the Setup UI in Jetpack Compose
|
||||
- Simplify screen based on previously discussed ideas and mock-ups
|
||||
- Improve backend setup logic
|
||||
- Implement base-UI for extensions and further continue development of existing Flex (FlorisBoard extension) format
|
||||
- Allows for a continuous experience of customizing FlorisBoard in different areas
|
||||
- Planned what will use Flex:
|
||||
- Themes
|
||||
- Layouts (Characters, symbols, numeric, ...)
|
||||
- Composers for non-Latin script languages
|
||||
- Word suggestion dictionaries (in 0.4.0)
|
||||
- Spell check dictionaries
|
||||
- User dictionaries (not in 0.3.14)
|
||||
- Other features that require only data and no logic (not in 0.3.14)
|
||||
- Maybe full backup of preferences? Not 100% confirmed though and may be pushed back
|
||||
- Theme rework part I:
|
||||
- Custom key corner radius
|
||||
- Custom key border color (not shadow!!)
|
||||
- Re-work theme internals so they use Flex extension format and FlexCSS
|
||||
- Improvement of the Smartbar
|
||||
- Allow to have multiple Smartbars
|
||||
- Better candidate view (in prep for 0.4.0)
|
||||
|
||||
### 0.3.15 & 0.3.16
|
||||
|
||||
- Hotfix releases for possible bugs in the preference rework, may be skipped.
|
||||
- Hotfix releases for possible bugs in the preference rework (in work)
|
||||
- Lots and lots of bug fixing in general (in work)
|
||||
- Preparation work for 0.4.0, fixing text state logic and use break iterator (done)
|
||||
- Reducing or getting rid of input lag some devices experience (done)
|
||||
- Clean up of project structure for better future development (done)
|
||||
|
||||
## 0.4.0
|
||||
|
||||
@@ -61,9 +33,9 @@ be introduced.
|
||||
|
||||
With this release the versioning scheme changes: the second number now indicates new features, changes in the third "
|
||||
patch" number now indicates bug fixes and minor feature additions for the stable track. The development cycle for each
|
||||
0.x release will have `-alphaXX`, `-betaXX` and `-rcXX` (release candidate) releases on the beta track for interested
|
||||
people to follow along the development. The first release to follow the new scheme will be `0.4.0-alpha01` on the beta
|
||||
track.
|
||||
0.x release will have `-alphaXX` (optional and only for large releases), `-betaXX` and `-rcXX` (release candidate)
|
||||
releases on the beta track for interested people to follow along the development. The first release to follow the new
|
||||
scheme will be `0.4.0-alpha01` on the beta track.
|
||||
|
||||
## 0.5.0
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
kotlin("kapt")
|
||||
kotlin("plugin.serialization")
|
||||
id("com.google.devtools.ksp")
|
||||
id("com.google.android.gms.oss-licenses-plugin")
|
||||
id("de.mannodermaus.android-junit5")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "dev.patrickgold.florisboard"
|
||||
compileSdk = 31
|
||||
buildToolsVersion = "31.0.0"
|
||||
ndkVersion = "22.1.7171670"
|
||||
@@ -29,21 +30,17 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "dev.patrickgold.florisboard"
|
||||
minSdk = 23
|
||||
minSdk = 24
|
||||
targetSdk = 31
|
||||
versionCode = 76
|
||||
versionName = "0.3.15"
|
||||
versionCode = 83
|
||||
versionName = "0.3.16"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments += mapOf(
|
||||
Pair("room.schemaLocation", "$projectDir/schemas"),
|
||||
Pair("room.incremental", "true"),
|
||||
Pair("room.expandProjection", "true")
|
||||
)
|
||||
}
|
||||
ksp {
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
arg("room.incremental", "true")
|
||||
arg("room.expandProjection", "true")
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -66,6 +63,9 @@ android {
|
||||
jniLibs {
|
||||
srcDirs("src/main/icu4c/prebuilt/jniLibs")
|
||||
}
|
||||
java {
|
||||
srcDirs("src/main/kotlin")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ android {
|
||||
create("beta") // Needed because by default the "beta" BuildType does not exist
|
||||
named("beta").configure {
|
||||
applicationIdSuffix = ".beta"
|
||||
versionNameSuffix = "-beta01"
|
||||
versionNameSuffix = "-beta03"
|
||||
proguardFiles.add(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||
|
||||
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_beta")
|
||||
@@ -127,9 +127,9 @@ android {
|
||||
named("release").configure {
|
||||
proguardFiles.add(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||
|
||||
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_release")
|
||||
resValue("mipmap", "floris_app_icon_round", "@mipmap/ic_app_icon_release_round")
|
||||
resValue("drawable", "floris_app_icon_foreground", "@drawable/ic_app_icon_release_foreground")
|
||||
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_stable")
|
||||
resValue("mipmap", "floris_app_icon_round", "@mipmap/ic_app_icon_stable_round")
|
||||
resValue("drawable", "floris_app_icon_foreground", "@drawable/ic_app_icon_stable_foreground")
|
||||
resValue("string", "floris_app_name", "@string/app_name")
|
||||
}
|
||||
}
|
||||
@@ -158,26 +158,27 @@ dependencies {
|
||||
implementation("androidx.compose.ui:ui:1.1.1")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview:1.1.1")
|
||||
implementation("androidx.core:core-ktx:1.7.0")
|
||||
implementation("androidx.core:core-splashscreen:1.0.0-beta01")
|
||||
implementation("androidx.core:core-splashscreen:1.0.0-beta02")
|
||||
implementation("androidx.emoji2:emoji2:1.1.0")
|
||||
implementation("androidx.emoji2:emoji2-views:1.1.0")
|
||||
implementation("androidx.navigation:navigation-compose:2.4.1")
|
||||
implementation("com.google.accompanist:accompanist-flowlayout:0.23.0")
|
||||
implementation("com.google.accompanist:accompanist-insets:0.23.0")
|
||||
implementation("com.google.accompanist:accompanist-systemuicontroller:0.23.0")
|
||||
implementation("androidx.navigation:navigation-compose:2.4.2")
|
||||
implementation("com.google.accompanist:accompanist-flowlayout:0.23.1")
|
||||
implementation("com.google.accompanist:accompanist-insets:0.23.1")
|
||||
implementation("com.google.accompanist:accompanist-systemuicontroller:0.23.1")
|
||||
implementation("dev.patrickgold.jetpref:jetpref-datastore-model:0.1.0-beta08")
|
||||
implementation("dev.patrickgold.jetpref:jetpref-datastore-ui:0.1.0-beta08")
|
||||
implementation("dev.patrickgold.jetpref:jetpref-material-ui:0.1.0-beta08")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
||||
implementation("io.github.reactivecircus.cache4k:cache4k:0.5.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
|
||||
implementation("androidx.room:room-runtime:2.4.2")
|
||||
kapt("androidx.room:room-compiler:2.4.2")
|
||||
ksp("androidx.room:room-compiler:2.4.2")
|
||||
|
||||
testImplementation("io.kotest:kotest-runner-junit5:5.1.0")
|
||||
testImplementation("io.kotest:kotest-assertions-core:5.1.0")
|
||||
testImplementation("io.kotest:kotest-property:5.1.0")
|
||||
testImplementation("io.kotest:kotest-runner-junit5:5.2.3")
|
||||
testImplementation("io.kotest:kotest-assertions-core:5.2.3")
|
||||
testImplementation("io.kotest:kotest-property:5.2.3")
|
||||
testImplementation("io.kotest.extensions:kotest-extensions-robolectric:0.5.0")
|
||||
testImplementation("nl.jqno.equalsverifier:equalsverifier:3.8.3")
|
||||
testImplementation("nl.jqno.equalsverifier:equalsverifier:3.10")
|
||||
|
||||
androidTestImplementation("androidx.test.ext", "junit", "1.1.2")
|
||||
androidTestImplementation("androidx.test.espresso", "espresso-core", "3.3.0")
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "d573e2ae2cbe7026957bc8d8fda291f3",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "clipboard_files",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER NOT NULL, `_display_name` TEXT NOT NULL, `_size` INTEGER NOT NULL, `mimeTypes` TEXT NOT NULL, PRIMARY KEY(`_id`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "displayName",
|
||||
"columnName": "_display_name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "size",
|
||||
"columnName": "_size",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "mimeTypes",
|
||||
"columnName": "mimeTypes",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"_id"
|
||||
],
|
||||
"autoGenerate": false
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_clipboard_files__id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_clipboard_files__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, 'd573e2ae2cbe7026957bc8d8fda291f3')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "6fbec9d7ea017f8aefac4fb84dbd5189",
|
||||
"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)",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"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, '6fbec9d7ea017f8aefac4fb84dbd5189')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "787af4a2df15bf9d2c0597519d3fb273",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "words",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `word` TEXT NOT NULL, `frequency` INTEGER NOT NULL, `locale` TEXT, `shortcut` TEXT)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "word",
|
||||
"columnName": "word",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "freq",
|
||||
"columnName": "frequency",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "locale",
|
||||
"columnName": "locale",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "shortcut",
|
||||
"columnName": "shortcut",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"_id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_words__id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_words__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, '787af4a2df15bf9d2c0597519d3fb273')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,7 @@
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="dev.patrickgold.florisboard">
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Permission needed to vibrate if the user has key press vibration enabled -->
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
@@ -52,8 +51,7 @@
|
||||
android:label="@string/floris_app_name"
|
||||
android:permission="android.permission.BIND_INPUT_METHOD"
|
||||
android:directBootAware="true"
|
||||
android:exported="true"
|
||||
tools:targetApi="n">
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.view.InputMethod"/>
|
||||
</intent-filter>
|
||||
@@ -105,7 +103,7 @@
|
||||
|
||||
<!-- Import File Bridging Activity -->
|
||||
<activity
|
||||
android:name="dev.patrickgold.florisboard.app.ui.ext.ImportFileActivity"
|
||||
android:name="dev.patrickgold.florisboard.app.ext.ImportFileActivity"
|
||||
android:icon="@mipmap/floris_app_icon"
|
||||
android:label="@string/settings__title"
|
||||
android:launchMode="singleTask"
|
||||
@@ -123,14 +121,14 @@
|
||||
|
||||
<!-- Crash Dialog Activity -->
|
||||
<activity
|
||||
android:name="dev.patrickgold.florisboard.crashutility.CrashDialogActivity"
|
||||
android:name="dev.patrickgold.florisboard.lib.crashutility.CrashDialogActivity"
|
||||
android:icon="@mipmap/floris_app_icon"
|
||||
android:label="@string/crash_dialog__title"
|
||||
android:theme="@style/CrashDialogTheme"/>
|
||||
|
||||
<!-- Clipboard Image File Provider -->
|
||||
<!-- Clipboard Media File Provider -->
|
||||
<provider
|
||||
android:name="dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardImagesProvider"
|
||||
android:name="dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardMediaProvider"
|
||||
android:authorities="${applicationId}.provider.clipboard"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
@@ -147,6 +145,17 @@
|
||||
android:resource="@xml/file_paths"/>
|
||||
</provider>
|
||||
|
||||
<!-- Disable default EmojiCompat initializer -->
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
<meta-data
|
||||
android:name="androidx.emoji2.text.EmojiCompatInitializer"
|
||||
tools:node="remove"/>
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"$": "ime.extension.keyboard",
|
||||
"meta": {
|
||||
"id": "org.florisboard.composers",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"title": "Default composers",
|
||||
"description": "Default composers which are always available.",
|
||||
"maintainers": [ "patrickgold <patrick@patrickgold.dev>" ],
|
||||
"maintainers": [ "patrickgold <patrick@patrickgold.dev>", "thanhhocse96 <thanh.hoquang@pm.me>" ],
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
"composers": [
|
||||
@@ -13,10 +13,10 @@
|
||||
{ "$": "hangul-unicode" },
|
||||
{ "$": "kana-unicode" },
|
||||
{ "$": "with-rules",
|
||||
"id": "basic-telex",
|
||||
"label": "Basic Telex",
|
||||
"id": "telex",
|
||||
"label": "Telex",
|
||||
"rules": {
|
||||
"aw": "ă", "aa": "â", "dd": "đ", "ee": "ê", "oo": "ô", "ow": "ơ", "uw": "ư", "w": "ư",
|
||||
"aw": "ă", "aa": "â", "dd": "đ", "ee": "ê", "oo": "ô", "ow": "ơ", "uw": "ư", "w": "ư",
|
||||
"uow": "ươ",
|
||||
"af": "à", "ar": "ả", "ax": "ã", "as": "á", "aj": "ạ",
|
||||
"ăf": "ằ", "ăr": "ẳ", "ăx": "ẵ", "ăs": "ắ", "ăj": "ặ",
|
||||
@@ -30,7 +30,7 @@
|
||||
"uf": "ù", "ur": "ủ", "ux": "ũ", "us": "ú", "uj": "ụ",
|
||||
"ưf": "ừ", "ưr": "ử", "ưx": "ữ", "ưs": "ứ", "ưj": "ự",
|
||||
"yf": "ỳ", "yr": "ỷ", "yx": "ỹ", "ys": "ý", "yj": "ỵ",
|
||||
"ăw": "aw", "âa": "aa", "đd": "dd", "êe": "ee", "ôo": "oo", "ơw": "ow", "ưw": "w",
|
||||
"ăw": "aw", "âa": "aa", "đd": "dd", "êe": "ee", "ôo": "oo", "ơw": "ow", "ưw": "w", "iêe": "iee",
|
||||
"ươw": "uow",
|
||||
"àf": "af", "ảr": "ar", "ãx": "ax", "ás": "as", "ạj": "aj",
|
||||
"ằf": "ăf", "ẳr": "ăr", "ẵx": "ăx", "ắs": "ăs", "ặj": "ăj",
|
||||
@@ -55,7 +55,562 @@
|
||||
"ờz": "ơ", "ởz": "ơ", "ỡz": "ơ", "ớz": "ơ", "ợz": "ơ",
|
||||
"ùz": "u", "ủz": "u", "ũz": "u", "úz": "u", "ụz": "u",
|
||||
"ừz": "ư", "ửz": "ư", "ữz": "ư", "ứz": "ư", "ựz": "ư",
|
||||
"ỳz": "y", "ỷz": "y", "ỹz": "y", "ýz": "y", "ỵz": "y"
|
||||
"ỳz": "y", "ỷz": "y", "ỹz": "y", "ýz": "y", "ỵz": "y",
|
||||
|
||||
"acw": "ăc", "amw": "ăm", "anw": "ăn", "apw": "ăp", "atw": "ăt", "angw": "ăng",
|
||||
"aca": "âc", "ama": "âm", "ana": "ân", "apa": "âp", "ata": "ât", "aua": "âu", "aya": "ây", "anga": "âng",
|
||||
"eme": "êm", "ene": "ên", "epe": "êp", "ete": "êt", "enhe": "ênh",
|
||||
"oio": "ôi","omo": "ôm", "ono": "ôn", "opo": "ôp", "oto": "ôt", "ongo": "ông",
|
||||
"omw": "ơm", "onw": "ơn", "opw": "ơp", "otw": "ơt",
|
||||
"uaw": "ưa", "uiw": "ưi", "umw": "ưm", "unw": "ưn", "utw": "ưt", "uuw": "ưu", "ungw": "ưng",
|
||||
"ieme": "iêm", "iene": "iên", "iepe": "iêp", "iete": "iêt", "ieue": "iêu", "ienge": "iêng",
|
||||
"uocw": "ươc", "uoiw": "ươi", "uomw": "ươm", "uonw": "ươn", "uotw": "ươt", "uongw": "ương",
|
||||
"uyene": "uyên", "uyete": "uyêt",
|
||||
"yeme": "yêm", "yene": "yên", "yete": "yêt", "yeue": "yêu", "yenge": "yêng",
|
||||
|
||||
"ăcw": "acw", "ămw": "amw", "ănw": "anw", "ăpw": "apw", "ătw": "atw", "ăngw": "angw",
|
||||
"âca": "aca", "âma": "ama", "âna": "ana", "âpa": "apa", "âta": "ata", "âua": "aua", "âya": "aya", "ânga": "anga",
|
||||
"ême": "eme", "êne": "ene", "êpe": "epe", "ête": "ete",
|
||||
"ôio": "oio", "ômo": "omo", "ôno": "ono", "ôpo": "opo", "ôto": "oto", "ôngo": "ongo",
|
||||
"ơmw": "omw", "ơnw": "onw", "ơpw": "opw", "ơtw": "otw",
|
||||
"ưaw": "uaw", "ưiw": "uiw", "ưmw": "umw", "ưnw": "unw" , "ưtw": "utw", "ưuw": "uuw", "ưngw": "ungw",
|
||||
"iême": "ieme", "iêne": "iene", "iêpe": "iepe", "iête": "iete", "iêue": "ieue", "iênge": "ienge",
|
||||
"ươcw": "uocw", "ươiw": "uoiw", "ươmw": "uomw", "ươnw": "uonw", "ươtw": "uotw", "ươngw": "uongw",
|
||||
"uyêne": "uyene", "uyêt": "uyete",
|
||||
"yême": "yeme", "yêne": "yene", "yête": "yete", "yêue": "yeue", "yênge": "yenge",
|
||||
|
||||
"acs": "ác", "acj": "ạc",
|
||||
"achs": "ách", "achj": "ạch",
|
||||
"ais": "ái", "aif": "ài", "air": "ải", "aix": "ãi", "aij": "ại",
|
||||
"ams": "ám", "amf": "àm", "amr": "ảm", "amx": "ãm", "amj": "ạm",
|
||||
"ans": "án" , "anf": "àn", "anr": "ản", "anx": "ãn", "anj": "ạn",
|
||||
"aos": "áo", "aof": "ào", "aor": "ảo", "aox": "ão", "aoj": "ạo",
|
||||
"aps":"áp", "apj": "ạp",
|
||||
"ats":"át", "atj": "ạt",
|
||||
"aus":"áu", "auf": "àu", "aur": "ảu", "aux": "ãu", "auj": "ạu",
|
||||
"ays": "áy", "ayf": "ày", "ayr": "ảy", "ayx": "ãy", "ayj": "ạy",
|
||||
"angs": "áng", "angf": "àng", "angr": "ảng", "angx": "ãng", "angj": "ạng",
|
||||
"anhs": "ánh", "anhf": "ành", "anhr": "ảnh", "anhx": "ãnh", "anhj": "ạnh",
|
||||
|
||||
"ács": "acs", "ạcj": "acj",
|
||||
"áchs": "achs", "ạchj": "achj",
|
||||
"áis": "ais", "àif": "aif", "ảir": "air", "ãix": "aix", "ạij": "aij",
|
||||
"áms": "ams", "àmf": "amf", "ảmr": "amr", "ãmx": "amx", "ạmj": "amj",
|
||||
"áns": "ans", "ànf": "anf", "ảnr": "anr", "ãnx": "anx", "ạnj": "anj",
|
||||
"áos": "aos", "àof": "aof", "ảor": "aor", "ãox": "aox", "ạoj":"aoj",
|
||||
"áps": "aps", "ạpj": "apj",
|
||||
"áts": "ats", "ạtj": "atj",
|
||||
"áus": "aus", "àuf": "auf", "ảur": "aur", "ãux": "aux", "ạuj": "auj",
|
||||
"áys": "ays", "àyf": "ayf", "ảyr": "ayr", "ãyx": "ayx", "ạyj": "ayj",
|
||||
"ángs": "angs", "àngf": "angf", "ảngr": "angr", "ãngx": "angx", "ạngj": "angj",
|
||||
"ánhs": "anhs", "ànhf": "anhf", "ảnhr": "anhr", "ãnhx": "anhx", "ạnhj": "anhj",
|
||||
|
||||
"ecs": "éc", "ecj": "ẹc",
|
||||
"ems": "ém", "emf": "èm", "emr": "ẻm", "emx": "ẽm", "emj": "ẹm",
|
||||
"ens": "én", "enf": "èn", "enr": "ẻn", "enx": "ẽn", "enj": "ẹn",
|
||||
"eps": "ép", "epj": "ẹp",
|
||||
"ets": "ét", "etj": "ẹt",
|
||||
"engs": "éng", "engf": "èng", "engr": "ẻng", "engx": "ẽng", "engj": "ẹng",
|
||||
"enhs": "énh", "enhf": "ènh", "enhr": "ẻnh", "enhx": "ẽnh", "enhj": "ẹnh",
|
||||
|
||||
"écs": "ecs", "ẹcj": "ecj",
|
||||
"éms": "ems", "èmf": "emf", "ẻmr": "emr", "ẽmx": "emx", "ẹmj": "emj",
|
||||
"éns": "ens", "ènf": "enf","ẻnr": "enr", "ẽnx": "enx", "ẹnj": "enj",
|
||||
"éps": "eps", "ẹpj": "epj",
|
||||
"éts": "ets", "ẹtj": "etj",
|
||||
"éngs": "engs", "èngf": "engf", "ẻngr": "engr", "ẽngx":"engx", "ẹngj": "engj",
|
||||
"énhs": "enhs", "ènhf": "enhf", "ẻnhr": "enhr", "ẽnh": "enhx", "ẹnh": "enhj",
|
||||
|
||||
"ias": "ía", "iaf": "ìa", "iar": "ỉa", "iax": "ĩa", "iaj": "ịa",
|
||||
"ims": "ím", "imf": "ìm", "imr": "ỉm", "imx": "ĩm", "imj": "ịm",
|
||||
"ins": "ín", "inf": "ìn", "inr": "ỉn", "inx": "ĩn", "inj": "ịn",
|
||||
"ips": "íp", "ipj": "ịp",
|
||||
"its": "ít", "itj": "ịt",
|
||||
"ius": "íu", "iuf": "ìu", "iur": "ỉu", "iux": "ĩu", "iuj": "ịu",
|
||||
"ichs": "ích", "ichj": "ịch",
|
||||
"inhs": "ính", "inhf": "ình", "inhr": "ỉnh", "inhx": "ĩnh", "inhj": "ịnh",
|
||||
|
||||
"ías": "ias", "ìaf": "iaf", "ỉar": "iar", "ĩax": "iax", "ịaj": "iaj",
|
||||
"íms": "ims", "ìmf": "imf", "ỉmr": "imr", "ĩmx": "imx", "ịmj": "imj",
|
||||
"íns": "ins", "ìnf": "inf", "ỉnr": "inr", "ĩnx": "inx", "ịnj": "inj",
|
||||
"íps": "ips", "ịpj": "ipj",
|
||||
"íts": "its", "ịtj": "itj",
|
||||
"íus": "ius", "ìuf": "iuf", "ỉur": "iur", "ĩux": "iux", "ịuj": "iuj",
|
||||
"íchs": "ichs", "ịchj": "ichj",
|
||||
"ínhs": "inhs", "ìnhf": "inhf", "ỉnhr": "inhr", "ĩnhx": "inhx", "ịnhj": "inhj",
|
||||
|
||||
"oas": "óa", "oaf": "òa", "oar": "ỏa", "oax": "õa", "oaj": "ọa",
|
||||
"ois": "ói", "oif": "òi", "oir": "ỏi", "oix": "õi", "oij": "ọi",
|
||||
"oms": "óm", "omf": "òm", "omr": "ỏm", "omx": "õm", "omj": "ọm",
|
||||
"ons": "ón", "onf": "òn", "onr": "ỏn", "onx": "õn", "onj": "ọn",
|
||||
"ops": "óp", "opj": "ọp",
|
||||
"ots": "ót", "otj": "ọt",
|
||||
"ongs": "óng", "ongf": "òng", "ongr": "ỏng", "ongx": "õng", "ongj": "ọng",
|
||||
|
||||
"óas": "oas", "òaf": "oaf", "ỏar": "oar", "õax": "oax", "ọaj": "oaj",
|
||||
"óis": "ois", "òif": "oif", "ỏir": "oir", "õix": "oix", "ọij": "oij",
|
||||
"óms": "oms", "òmf": "omf", "ỏmr": "omr", "õmx": "omx", "ọmj": "omj",
|
||||
"óns": "ons", "ònf": "onf", "ỏnr": "onr", "õnx": "onx", "ọnj": "onj",
|
||||
"óps": "ops", "ọpj": "opj",
|
||||
"óts": "ots", "ọtj": "otj",
|
||||
"óngs": "ongs", "òngf": "ongf", "ỏngr": "ongr", "õngx": "ongx", "ọngj": "ongj",
|
||||
|
||||
"uas": "úa", "uaf": "ùa", "uar": "ủa", "uax": "ũa", "uaj": "ụa",
|
||||
"uis": "úi", "uif": "ùi", "uir": "ủi", "uix": "ũi", "uij": "ụi",
|
||||
"ums": "úm", "umf": "ùm", "umr": "ủm", "umx": "ũm", "umj": "ụm",
|
||||
"uns": "ún", "unf": "ùn", "unr": "ủn", "unx": "ũn", "unj": "ụn",
|
||||
"ups": "úp", "upj": "ụp",
|
||||
"uts": "út", "utj": "ụt",
|
||||
"uus": "úu", "uuf": "ùu", "uur": "ủu", "uux": "ũu", "uuj": "ụu",
|
||||
"uys": "úy", "uyf": "ùy", "uyr": "ủy", "uyx": "ũy", "uyj": "ụy",
|
||||
"ungs": "úng", "ungf": "ùng", "ungr": "ủng", "ungx": "ũng", "ungj": "ụng",
|
||||
|
||||
"úas": "uas", "ùaf": "uaf", "ủar": "uar", "ũax": "uax", "ụaj": "uaj",
|
||||
"úis": "uis", "ùif": "uif", "ủir": "uir", "ũix": "uix", "ụij": "uij",
|
||||
"úms": "ums", "ùmf": "umf", "ủmr": "umr", "ũmx": "umx", "ụmj": "umj",
|
||||
"úns": "uns", "ùnf": "unf", "ủnr": "unr", "ũnx": "unx", "ụnj": "unj",
|
||||
"úps": "ups", "ụpj": "upj",
|
||||
"úts": "uts", "ụtj": "utj",
|
||||
"úus": "uus", "ùuf": "uuf", "ủur": "uur", "ũux": "uux", "ụuj": "uuj",
|
||||
"úu ": "uus", "ùu ": "uuf", "ủu ": "uur", "ũu ": "uux", "ụu ": "uuj",
|
||||
"úys": "uys", "ùyf": "uyf", "ủyr": "uyr", "ũyx": "uyx", "ụyj": "uyj",
|
||||
"úngs": "ungs", "ùngf": "ungf", "ủngr": "ungr", "ũngx": "ungx", "ụngj": "ungj",
|
||||
|
||||
"ăcs": "ắc", "ăcj": "ặc",
|
||||
"ácw": "ắc", "ạcw": "ặc",
|
||||
"ăms": "ắm", "ămf": "ằm", "ămr": "ẳm", "ămx": "ẵm", "ămj": "ặm",
|
||||
"ámw": "ắm", "àmw": "ằm", "ảmw": "ẳm", "ãmw": "ẵm", "ạmw": "ặm",
|
||||
"ăns": "ắn", "ănf": "ằn", "ănr": "ẳn", "ănx": "ẵn", "ănj": "ặn",
|
||||
"ánw": "ắn", "ànw": "ằn", "ảnw": "ẳn", "ãnw": "ẵn", "ạnw": "ặn",
|
||||
"ăps": "ắp", "ăpj": "ặp",
|
||||
"ápw": "ắp", "ạpw": "ặp",
|
||||
"ăts": "ắt", "ătj": "ặt",
|
||||
"átw": "ắt", "ạtw": "ặt",
|
||||
"ăngs": "ắng", "ăngf": "ằng", "ăngr": "ẳng", "ăngx": "ẵng", "ăngj": "ặng",
|
||||
"ángw": "ắng", "àngw": "ằng", "ảngw": "ẳng", "ãngw":"ẵng", "ạngw": "ặng",
|
||||
|
||||
"ắcw": "ácw", "ắcs": "ăcs", "ăcsw": "acsw", "ácws": "acws",
|
||||
"ặcw": "ạcw", "ặcj": "ăcj", "ăcjw": "acjw", "ạcwj": "acwj",
|
||||
"ắms": "ăms", "ắmw": "ámw", "ămsw": "amsw", "ámws": "amws",
|
||||
"ằmf": "ămf", "ằmw": "àmw", "ămfw": "amfw", "àmwf": "amwf",
|
||||
"ẳmr": "ămr", "ẳmw": "ảmw", "ămrw": "amrw", "ảmwr": "amwr",
|
||||
"ẵmx": "ămx", "ẵmw": "ãmw", "ămxw": "amxw", "ãmwx": "amwx",
|
||||
"ặmj": "ămj", "ặmw": "ạmw", "ămjw": "amjw", "ạmwj": "amwj",
|
||||
"ắns": "ăns", "ắnw": "ánw", "ănsw": "answ", "ánws": "anws",
|
||||
"ằnf": "ănf", "ằnw": "ànw", "ănfw": "anfw", "ànwf": "anwf",
|
||||
"ẳnr": "ănr", "ẳnw": "ảnw", "ănrw": "anrw", "ảnwr": "anwr",
|
||||
"ẵnx": "ănx", "ẵnw": "ãnw", "ănxw": "anxw", "ãnwx": "anwx",
|
||||
"ặnj": "ănj", "ặnw": "ạnw", "ănjw": "anjw", "ạnwj": "anwj",
|
||||
"ắps": "ăps", "ắpw": "ápw", "ăpsw": "apsw", "ápws": "apws",
|
||||
"ặpj": "ăpj", "ặpw": "ạpw", "ăpjw": "apjw", "ạpwj": "apwj",
|
||||
"ắts": "ăts", "ắtw": "átw", "ătsw": "atws", "átws": "atws",
|
||||
"ặtj": "ătj", "ặtw": "ạtw", "ătjw": "atjw", "ạtwj": "atwj",
|
||||
"ắngs": "ăngs", "ắngw": "ángw", "ăngsw": "angsw", "ángws": "angws",
|
||||
"ằngf": "ăngf", "ằngw": "àngw", "ăngfw": "angfw", "àngwf": "angwf",
|
||||
"ẳngr": "ăngr", "ẳngw": "ảngw", "ăngrw": "angrw", "ảngwr": "angwr",
|
||||
"ẵngx": "ăngx", "ẵngw": "ãngw", "ăngxw": "angxw", "ãngwx": "angwx",
|
||||
"ặngj": "ăngj", "ặngw": "ạngw", "ăngjw": "angjw", "ạngwj": "angwj",
|
||||
|
||||
"âcs": "ấc", "âcj": "ậc",
|
||||
"áca": "ấc", "ạca": "ậc",
|
||||
"âms": "ấm", "âmf": "ầm", "âmr": "ẩm", "âmx": "ẫm", "âmj": "ậm",
|
||||
"áma": "ấm", "àma": "ầm", "ảma": "ẩm", "ãma": "ẫm", "ạma": "ậm",
|
||||
"âns": "ấn", "ânf": "ần", "ânr": "ẩn", "ânx": "ẫn", "ânj": "ận",
|
||||
"ána": "ấn", "àna": "ần", "ảna": "ẩn", "ãna": "ẫn", "ạna": "ận",
|
||||
"âps": "ấp", "âpj": "ập",
|
||||
"ápa": "ấp", "ạpa": "ập",
|
||||
"âts": "ất", "âtj": "ật",
|
||||
"áta": "ất", "ạta": "ật",
|
||||
"âus": "ấu", "âuf": "ầu", "âur": "ẩu", "âux": "ẫu", "âuj": "ậu",
|
||||
"áua": "ấu", "àua": "ầu", "ảua": "ẩu", "ãua": "ẫu", "ạua": "ậu",
|
||||
"âys": "ấy", "âyf": "ầy", "âyr": "ẩy", "âyx": "ẫy", "âyj": "ậy",
|
||||
"áya": "ấy", "àya": "ầy", "ảya": "ẩy", "ãya": "ẫy", "ạya": "ậy",
|
||||
"ângs": "ấng", "ângf": "ầng", "ângr": "ẩng", "ângx": "ẫng", "ângj": "ậng",
|
||||
"ánga": "ấng", "ànga": "ầng", "ảnga": "ẩng", "ãnga": "ẫng", "ạnga": "ậng",
|
||||
|
||||
"ấcs": "âcs", "ấca": "áca", "âcsa": "acsa", "ácas": "acas",
|
||||
"ậcj": "âcj", "ậca": "ạca", "âcja": "acja", "ạcaj": "acaj",
|
||||
"ấms": "âms", "ấma": "áma", "âmsa": "amsa", "ámas": "amas",
|
||||
"ầmf": "âmf", "ầma": "àma", "âmfa": "amfa", "àmaf": "amaf",
|
||||
"ẩmr": "âmr", "ẩma": "ảma", "âmra": "amra", "ảmar": "amar",
|
||||
"ẫmx": "âmx", "ẫma": "ãma", "âmxa": "amxa", "ãmax": "amax",
|
||||
"ậmj": "âmj", "ậma": "ạma", "âmja": "amja", "ạmaj": "amaj",
|
||||
"ấns": "âns", "ấna": "ána", "ânsa": "ansa", "ánas": "anas",
|
||||
"ầnf": "ânf", "ầna": "àna", "ânfa": "anfa", "ànaf": "anaf",
|
||||
"ẩnr": "ânr", "ẩna": "ảna", "ânra": "anra", "ảnar": "anar",
|
||||
"ẫnx": "ânx", "ẫna": "ãna", "ânxa": "anxa", "ãnax": "anax",
|
||||
"ậnj": "ânj", "ậna": "ạna", "ânja": "anja", "ạnaj": "anaj",
|
||||
"ấps": "âps", "ấpa": "ápa", "âpsa": "apsa", "ápas": "apas",
|
||||
"ậpj": "âpj", "ậpa": "ạpa", "âpja": "apja", "ạpaj": "apaj",
|
||||
"ấts": "âts", "ấta": "áta", "âtsa": "atas", "átas": "atas",
|
||||
"ậtj": "âtj", "ậta": "ạta", "âtja": "atja", "ạtaj": "ataj",
|
||||
"ấus": "âus", "ấua": "áua", "âusa": "ausa", "áuas": "auas",
|
||||
"ầuf": "âuf", "ầua": "àua", "âufa": "aufa", "àuaf": "auaf",
|
||||
"ẩur": "âur", "ẩua": "ảua", "âura": "aura", "ảuar": "auar",
|
||||
"ẫux": "âux", "ẫua": "ãua", "âuxa": "auxa", "ãuax": "auax",
|
||||
"ậuj": "âuj", "ậua": "ạua", "âuja": "auja", "ạuaj": "auaj",
|
||||
"ấys": "âys", "ấya": "áya", "âysa": "aysa", "áyas": "ayas",
|
||||
"ầyf": "âyf", "ầya": "àya", "âyfa": "ayfa", "àyaf": "ayaf",
|
||||
"ẩyr": "âyr", "ẩya": "ảya", "âyra": "ayra", "ảyar": "ayar",
|
||||
"ẫyx": "âyx", "ẫya": "ãya", "âyxa": "ayxa", "ãyax": "ayax",
|
||||
"ậyj": "âyj", "ậya": "ạya", "âyja": "ayja", "ạyaj": "ayaj",
|
||||
"ấngs": "ângs", "ấnga": "ánga", "ângsa": "angsa", "ángas": "angas",
|
||||
"ầngf": "ângf", "ầnga": "ànga", "ângfa": "angfa", "àngaf": "angaf",
|
||||
"ẩngr": "ângr", "ẩnga": "ảnga", "ângra": "angra", "ảngar": "angar",
|
||||
"ẫngx": "ângx", "ẫnga": "ãnga", "ângxa": "angxa", "ãngax": "angax",
|
||||
"ậngj": "ângj", "ậnga": "ạnga", "ângja": "angja", "ạngaj": "angaj",
|
||||
|
||||
"êcs": "ếc", "êcj": "ệc",
|
||||
"éce": "ếc", "ẹce": "ệc",
|
||||
"êms": "ếm", "êmf": "ềm", "êmr": "ểm", "êmx": "ễm", "êmj": "ệm",
|
||||
"éme": "ếm", "ème": "ềm", "ẻme": "ểm", "ẽme": "ễm", "ẹme": "ệm",
|
||||
"êns": "ến", "ênf": "ền", "ênr": "ển", "ênx": "ễn", "ênj": "ện",
|
||||
"éne": "ến", "ène": "ền", "ẻne": "ển", "ẽne": "ễn", "ẹne": "ện",
|
||||
"êps": "ếp", "êpj": "ệp",
|
||||
"épe": "ếp", "ẹpe": "ệp",
|
||||
"êts": "ết", "êtj": "ệt",
|
||||
"éte": "ết", "ẹte": "ệt",
|
||||
"êchs": "ếch", "êchj": "ệch",
|
||||
"echs": "éch", "echj": "ẹch",
|
||||
"éche": "ếch", "ẹche": "ệch",
|
||||
"ênhs": "ếnh", "ênhf": "ềnh", "ênhr": "ểnh", "ênhx": "ễnh", "ênhj": "ệnh",
|
||||
"énhe": "ếnh", "ènhe": "ềnh", "ẻnhe": "ểnh", "ẽnhe": "ễnh", "ẹnhe": "ệnh",
|
||||
|
||||
"ếms": "êms", "ếme": "éme", "êmse": "emse", "émes": "emes",
|
||||
"ềmf": "êmf", "ềme": "ème", "êmfe": "emfe", "èmef": "emef",
|
||||
"ểmr": "êmr", "ểme": "ẻme", "êmre": "emre", "ẻmer": "emer",
|
||||
"ễmx": "êmx", "ễme": "ẽme", "êmxe": "emxe", "ẽmex": "emex",
|
||||
"ệmj": "êmj", "ệme": "ẹme", "êmje": "emje", "ẹmej": "emej",
|
||||
"ếns": "êns", "ếne": "éne", "ênse": "ense", "énes": "enes",
|
||||
"ềnf": "ênf", "ềne": "ène", "ênfe": "enfe", "ènef": "enef",
|
||||
"ểnr": "ênr", "ểne": "ẻne", "ênre": "enre", "ẻner": "ener",
|
||||
"ễnx": "ênx", "ễne": "ẽne", "ênxe": "enxe", "ẽnex": "enex",
|
||||
"ệnj": "ênj", "ệne": "ẹne", "ênje": "enje", "ẹnej": "enej",
|
||||
"ếps": "êps", "ếpe": "épe", "êpse": "epse", "épes": "epes",
|
||||
"ệpj": "êpj", "ệpe": "ẹpe", "êpje": "epje", "ẹpej": "epej",
|
||||
"ếts": "êts", "ếte": "éte", "êtse": "etes", "étes": "etes",
|
||||
"ệtj": "êtj", "ệte": "ẹte", "êtje": "etje", "ẹtej": "etej",
|
||||
"ếchs": "êchs", "ếche": "éche", "êchse": "eches", "éches": "eches",
|
||||
"ệchj": "êchj", "ệche": "ẹche", "êchje": "echje", "ẹchej": "echej",
|
||||
"ếnhs": "ênhs", "ếnhe": "énhe", "ênhse": "enhse", "énhes": "enhes",
|
||||
"ềnhf": "ênhf", "ềnhe": "ènhe", "ênhfe": "enhfe", "ènhef": "enhef",
|
||||
"ểnhr": "ênhr", "ểnhe": "ẻnhe", "ênhre": "enhre", "ẻnher": "enher",
|
||||
"ễnhx": "ênhx", "ễnhe": "ẽnhe", "ênhxe": "enhxe", "ẽnhex": "enhex",
|
||||
"ệnhj": "ênhj", "ệnhe": "ẹnhe", "ênhje": "enhje", "ẹnhej": "enhej",
|
||||
|
||||
"ôcs": "ốc", "ôcj": "ộc",
|
||||
"óco": "ốc", "ọco": "ộc",
|
||||
"ôis": "ối", "ôif": "ồi", "ôir": "ổi", "ôix": "ỗi", "ôij": "ội",
|
||||
"óio": "ối", "òio": "ồi", "ỏio": "ổi", "õio": "ỗi", "ọio": "ội",
|
||||
"ôms": "ốm", "ômf": "ồm", "ômr": "ổm", "ômx": "ỗm", "ômj": "ộm",
|
||||
"ómo": "ốm", "òmo": "ồm", "ỏmo": "ổm", "õmo": "ỗm", "ọmo": "ộm",
|
||||
"ôns": "ốn", "ônf": "ồn", "ônr": "ổn", "ônx": "ỗn", "ônj": "ộn",
|
||||
"óno": "ốn", "òno": "ồn", "ỏno": "ổn", "õno": "ỗn", "ọno": "ộn",
|
||||
"ôps": "ốp", "ôpj": "ộp",
|
||||
"ópo": "ốp", "ọpo": "ộp",
|
||||
"ôts": "ốt", "ôtj": "ột",
|
||||
"óto": "ốt", "ọto": "ột",
|
||||
"ôngs": "ống", "ôngf": "ồng", "ôngr": "ổng", "ôngx": "ỗng", "ôngj": "ộng",
|
||||
"óngo": "ống", "òngo": "ồng", "ỏngo": "ổng", "õngo": "ỗng", "ọngo": "ộng",
|
||||
|
||||
"ốcs": "ôcs", "ốco": "óco", "ôcso": "ocso", "ócos": "ocos",
|
||||
"ộcj": "ôcj", "ộco": "ọco", "ôcjo": "ocjo", "ọcoj": "ocoj",
|
||||
"ốis": "ôis", "ốio": "óio", "ôiso": "oiso", "óios": "oios",
|
||||
"ồif": "ôif", "ồio": "òio", "ôifo": "oifo", "òiof": "oiof",
|
||||
"ổir": "ôir", "ổio": "ỏio", "ôiro": "oiro", "ỏior": "oior",
|
||||
"ỗix": "ôix", "ỗio": "õio", "ôixo": "oixo", "õiox": "oiox",
|
||||
"ộij": "ôij", "ộio": "ọio", "ôijo": "oijo", "ọioj": "oioj",
|
||||
"ốms": "ôms", "ốmo": "ómo", "ômso": "omso", "ómos": "omos",
|
||||
"ồmf": "ômf", "ồmo": "òmo", "ômfo": "omfo", "òmof": "omof",
|
||||
"ổmr": "ômr", "ổmo": "ỏmo", "ômro": "omro", "ỏmor": "omor",
|
||||
"ỗmx": "ômx", "ỗmo": "õmo", "ômxo": "omxo", "õmox": "omox",
|
||||
"ộmj": "ômj", "ộmo": "ọmo", "ômjo": "omjo", "ọmoj": "omoj",
|
||||
"ốns": "ôns", "ốno": "óno", "ônso": "onso", "ónos": "onos",
|
||||
"ồnf": "ônf", "ồno": "òno", "ônfo": "onfo", "ònof": "onof",
|
||||
"ổnr": "ônr", "ổno": "ỏno", "ônro": "onro", "ỏnor": "onor",
|
||||
"ỗnx": "ônx", "ỗno": "õno", "ônxo": "onxo", "õnox": "onox",
|
||||
"ộnj": "ônj", "ộno": "ọno", "ônjo": "onjo", "ọnoj": "onoj",
|
||||
"ốps": "ôps", "ốpo": "ópo", "ôpso": "opso", "ópos": "opos",
|
||||
"ộpj": "ôpj", "ộpo": "ọpo", "ôpjo": "opjo", "ọpoj": "opoj",
|
||||
"ốts": "ôts", "ốto": "óto", "ôtso": "otso", "ótos": "otos",
|
||||
"ộtj": "ôtj", "ộto": "ọto", "ôtjo": "otjo", "ọtoj": "otoj",
|
||||
"ốngs": "ôngs", "ốngo": "óngo", "ôngso": "ongso", "óngos": "ongos",
|
||||
"ồngf": "ôngf", "ồngo": "òngo", "ôngfo": "ongfo", "òngof": "ongof",
|
||||
"ổngr": "ôngr", "ổngo": "ỏngo", "ôngro": "ongro", "ỏngor": "ongor",
|
||||
"ỗngx": "ôngx", "ỗngo": "õngo", "ôngxo": "ongxo", "õngox": "ongox",
|
||||
"ộngj": "ôngj", "ộngo": "ọngo", "ôngjo": "ongjo", "ọngoj": "ongoj",
|
||||
|
||||
"ơis": "ới", "ơif": "ời", "ơir": "ởi", "ơix": "ỡi", "ơij": "ợi",
|
||||
"óiw": "ới", "òiw": "ời", "ỏiw": "ởi", "õiw": "ỡi", "ọiw": "ợi",
|
||||
"ơms": "ớm", "ơmf": "ờm", "ơmr": "ởm", "ơmx": "ỡm", "ơmj": "ợm",
|
||||
"ómw": "ớm", "òmw": "ờm", "ỏmw": "ởm", "õmw": "ỡm", "ọmw": "ợm",
|
||||
"ơns": "ớn", "ơnf": "ờn", "ơnr": "ởn", "ơnx": "ỡn", "ơnj": "ợn",
|
||||
"ónw": "ớn", "ònw": "ờn", "ỏnw": "ởn", "õnw": "ỡn", "ọnw": "ợn",
|
||||
"ơps": "ớp", "ơpj": "ợp",
|
||||
"ópw": "ớp", "ọpw": "ợp",
|
||||
"ơts": "ớt", "ơtj": "ợt",
|
||||
"ótw": "ớt", "ọtw": "ợt",
|
||||
|
||||
"ớis": "ơis", "ớiw": "óiw", "ơisw": "oisw", "óiws": "oiws",
|
||||
"ờif": "ơif", "ờiw": "òiw", "ơifw": "oifw", "òiwf": "oiwf",
|
||||
"ởir": "ơir", "ởiw": "ỏiw", "ơirw": "oirw", "ỏiwr": "oiwr",
|
||||
"ỡix": "ơix", "ỡiw": "õiw", "ơixw": "oixw", "õiwx": "oiwx",
|
||||
"ợij": "ơij", "ợiw": "ọiw", "ơijw": "oijw", "ọiwj": "oiwj",
|
||||
"ớms": "ơms", "ớmw": "ómw", "ơmsw": "omsw", "ómws": "omws",
|
||||
"ờmf": "ơmf", "ờmw": "òmw", "ơmfw": "omfw", "òmwf": "omwf",
|
||||
"ởmr": "ơmr", "ởmw": "ỏmw", "ơmrw": "omrw", "ỏmwr": "omwr",
|
||||
"ỡmx": "ơmx", "ỡmw": "õmw", "ơmxw": "omxw", "õmwx": "omwx",
|
||||
"ợmj": "ơmj", "ợmw": "ọmw", "ơmjw": "omjw", "ọmwj": "omwj",
|
||||
"ớns": "ơns", "ớnw": "ónw", "ơnsw": "onsw", "ónws": "onws",
|
||||
"ờnf": "ơnf", "ờnw": "ònw", "ơnfw": "onfw", "ònwf": "onwf",
|
||||
"ởnr": "ơnr", "ởnw": "ỏnw", "ơnrw": "onrw", "ỏnwr": "onwr",
|
||||
"ỡnx": "ơnx", "ỡnw": "õnw", "ơnxw": "onxw", "õnwx": "onwx",
|
||||
"ợnj": "ơnj", "ợnw": "ọnw", "ơnjw": "onjw", "ọnwj": "onwj",
|
||||
"ớps": "ơps", "ớpw": "ópw", "ơpsw": "opsw", "ópws": "opws",
|
||||
"ợpj": "ơpj", "ợpw": "ọpw", "ơpjw": "opjw", "ọpwj": "opwj",
|
||||
"ớts": "ơts", "ớtw": "ótw", "ơtsw": "otsw", "ótws": "otws",
|
||||
"ợtj": "ơtj", "ợtw": "ọtw", "ơtjw": "otjw", "ọtwj": "otwj",
|
||||
|
||||
"ưas": "ứa", "ưaf": "ừa", "ưar": "ửa", "ưax": "ữa", "ưaj": "ựa",
|
||||
"úaw": "ứa", "ùaw": "ừa", "ủaw": "ửa", "ũaw": "ữa", "ụaw": "ựa",
|
||||
"ưis": "ứi", "ưif": "ừi", "ưir": "ửi", "ưix": "ữi", "ưij": "ựi",
|
||||
"úiw": "ứi", "ùiw": "ừi", "ủiw": "ửi", "ũiw": "ữi", "ụiw": "ựi",
|
||||
"ưms": "ứm", "ưmf": "ừm", "ưmr": "ửm", "ưmx": "ữm", "ưmj": "ựm",
|
||||
"úmw": "ứm", "ùmw": "ừm", "ủmw": "ửm", "ũmw": "ữm", "ụmw": "ựm",
|
||||
"ưns": "ứn", "ưnf": "ừn", "ưnr": "ửn", "ưnx": "ữn", "ưnj": "ựn",
|
||||
"únw": "ứn", "ùnw": "ừn", "ủnw": "ửn", "ũnw": "ữn", "ụnw": "ựn",
|
||||
"ưts": "ứt", "ưtj": "ựt",
|
||||
"útw": "ứt", "ụtw": "ựt",
|
||||
"ưus": "ứu", "ưuf": "ừu", "ưur": "ửu", "ưux": "ữu", "ưuj": "ựu",
|
||||
"úuw": "ứu", "ùuw": "ừu", "ủuw": "ửu", "ũuw": "ữu", "ụuw": "ựu",
|
||||
"ưngs": "ứng", "ưngf": "ừng", "ưngr": "ửng", "ưngx": "ững", "ưngj": "ựng",
|
||||
"úngw": "ứng", "ùngw": "ừng", "ủngw": "ửng", "ũngw": "ững", "ụngw": "ựng",
|
||||
|
||||
"ứas": "ưas", "ứaw": "úaw", "ưasw": "uasw", "úaws": "uaws",
|
||||
"ừaf": "ưaf", "ừaw": "ùaw", "ưafw": "uafw", "ùawf": "uawf",
|
||||
"ửar": "ưar", "ửaw": "ủaw", "ưarw": "uarw", "ủawr": "uawr",
|
||||
"ữax": "ưax", "ữaw": "ũaw", "ưaxw": "uaxw", "ũawx": "uawx",
|
||||
"ựaj": "ưaj", "ựaw": "ụaw", "ưajw": "uajw", "ụawj": "uawj",
|
||||
"ứis": "ưis", "ứiw": "úiw", "ưisw": "uisw", "úiws": "uiws",
|
||||
"ừif": "ưif", "ừiw": "ùiw", "ưifw": "uifw", "ùiwf": "uiwf",
|
||||
"ửir": "ưir", "ửiw": "ủiw", "ưirw": "uirw", "ủiwr": "uiwr",
|
||||
"ữix": "ưix", "ữiw": "ũiw", "ưixw": "uixw", "ũiwx": "uiwx",
|
||||
"ựij": "ưij", "ựiw": "ụiw", "ưijw": "uijw", "ụiwj": "uiwj",
|
||||
"ứms": "ưms", "ứmw": "úmw", "ưmsw": "umsw", "úmws": "umws",
|
||||
"ừmf": "ưmf", "ừmw": "ùmw", "ưmfw": "umfw", "ùmwf": "umwf",
|
||||
"ửmr": "ưmr", "ửmw": "ủmw", "ưmrw": "umrw", "ủmwr": "umwr",
|
||||
"ữmx": "ưmx", "ữmw": "ũmw", "ưmxw": "umxw", "ũmwx": "umwx",
|
||||
"ựmj": "ưmj", "ựmw": "ụmw", "ưmjw": "umjw", "ụmwj": "umwj",
|
||||
"ứns": "ưns", "ứnw": "únw", "ưnsw": "unsw", "únws": "unws",
|
||||
"ừnf": "ưnf", "ừnw": "ùnw", "ưnfw": "unfw", "ùnwf": "unwf",
|
||||
"ửnr": "ưnr", "ửnw": "ủnw", "ưnrw": "unrw", "ủnwr": "unwr",
|
||||
"ữnx": "ưnx", "ữnw": "ũnw", "ưnxw": "unxw", "ũnwx": "unwx",
|
||||
"ựnj": "ưnj", "ựnw": "ụnw", "ưnjw": "unjw", "ụnwj": "unwj",
|
||||
"ứts": "ưts", "ứtw": "útw", "ưtsw": "utsw", "útws": "utws",
|
||||
"ựtj": "ưtj", "ựtw": "ụtw", "ưtjw": "utjw", "ụtwj": "utwj",
|
||||
"ứus": "ưus", "ứuw": "úuw", "ưusw": "uusw", "úuws": "uuws",
|
||||
"ừuf": "ưuf", "ừuw": "ùuw", "ưufw": "uufw", "ùuwf": "uuwf",
|
||||
"ửur": "ưur", "ửuw": "ủuw", "ưurw": "uurw", "ủuwr": "uuwr",
|
||||
"ữux": "ưux", "ữuw": "ũuw", "ưuxw": "uuxw", "ũuwx": "uuwx",
|
||||
"ựuj": "ưuj", "ựuw": "ụuw", "ưujw": "uujw", "ụuwj": "uuwj",
|
||||
"ứngs": "ưngs", "ứngw": "úngw", "ưngsw": "ungsw", "úngws": "ungws",
|
||||
"ừngf": "ưngf", "ừngw": "ùngw", "ưngfw": "ungfw", "ùngwf": "ungwf",
|
||||
"ửngr": "ưngr", "ửngw": "ủngw", "ưngrw": "ungrw", "ủngwr": "ungwr",
|
||||
"ữngx": "ưngx", "ữngw": "ũngw", "ưngxw": "ungxw", "ũngwx": "ungwx",
|
||||
"ựngj": "ưngj", "ựngw": "ụngw", "ưngjw": "ungjw", "ụngwj": "ungwj",
|
||||
|
||||
"iems": "iém", "iemf": "ièm", "iemr": "iẻm", "iemx": "iẽm", "iemj": "iẹm",
|
||||
"iéme": "iếm", "ième": "iềm", "iẻme": "iểm", "iẽme": "iễm", "iẹme": "iệm",
|
||||
"iêms": "iếm", "iêmf": "iềm", "iêmr": "iểm", "iêmx": "iễm", "iêmj": "iệm",
|
||||
"iens": "ién", "ienf": "ièn", "ienr": "iẻn", "ienx": "iẽn", "ienj": "iẹn",
|
||||
"iéne": "iến", "iène": "iền", "iẻne": "iển", "iẽne": "iễn", "iẹne": "iện",
|
||||
"iêns": "iến", "iênf": "iền", "iênr": "iển", "iênx": "iễn", "iênj": "iện",
|
||||
"ieps": "iép", "iepj": "iẹp",
|
||||
"iépe": "iếp", "iẹpe": "iệp",
|
||||
"iêps": "iếp", "iêpj": "iệp",
|
||||
"iets": "iét", "ietj": "iẹt",
|
||||
"iéte": "iết", "iẹte": "iệt",
|
||||
"iêts": "iết", "iêtj": "iệt",
|
||||
"ieus": "iéu", "ieuf": "ièu", "ieur": "iẻu", "ieux": "iẽu", "ieuj": "iẹu",
|
||||
"iéue": "iếu", "ièue": "iều", "iẻue": "iểu", "iẽue": "iễu", "iẹue": "iệu",
|
||||
"iêus": "iếu", "iêuf": "iều", "iêur": "iểu", "iêux": "iễu", "iêuj": "iệu",
|
||||
"iengs": "iéng", "iengf": "ièng", "iengr": "iẻng", "iengx": "iẽng", "iengj": "iẹng",
|
||||
"iénge": "iếng", "iènge": "iềng", "iẻnge": "iểng", "iẽnge": "iễng", "iẹnge": "iệng",
|
||||
"iêngs": "iếng", "iêngf": "iềng", "iêngr": "iểng", "iêngx": "iễng", "iêngj": "iệng",
|
||||
|
||||
"iếms": "iêms", "iếme": "iéme", "iêmse": "iemse", "iémes": "iemes",
|
||||
"iềmf": "iêmf", "iềme": "ième", "iêmfe": "iemfe", "ièmef": "iemef",
|
||||
"iểmr": "iêmr", "iểme": "iẻme", "iêmre": "iemre", "iẻmer": "iemer",
|
||||
"iễmx": "iêmx", "iễme": "iẽme", "iêmxe": "iemxe", "iẽmex": "iemex",
|
||||
"iệmj": "iêmj", "iệme": "iẹme", "iêmje": "iemje", "iẹmej": "iemej",
|
||||
"iếns": "iêns", "iếne": "iéne", "iênse": "iense", "iénes": "ienes",
|
||||
"iềnf": "iênf", "iềne": "iène", "iênfe": "ienfe", "iènef": "ienef",
|
||||
"iểnr": "iênr", "iểne": "iẻne", "iênre": "ienre", "iẻner": "iener",
|
||||
"iễnx": "iênx", "iễne": "iẽne", "iênxe": "ienxe", "iẽnex": "ienex",
|
||||
"iệnj": "iênj", "iệne": "iẹne", "iênje": "ienje", "iẹnej": "ienej",
|
||||
"iếps": "iêps", "iếpe": "iépe", "iêpse": "iepse", "iépes": "iepes",
|
||||
"iệpj": "iêpj", "iệpe": "iẹpe", "iêpje": "iepje", "iẹpej": "iepej",
|
||||
"iếts": "iêts", "iếte": "iéte", "iêtse": "ietse", "iétes": "ietes",
|
||||
"iệtj": "iêtj", "iệte": "iẹte", "iêtje": "ietje", "iẹtej": "ietej",
|
||||
"iếus": "iêus", "iếue": "iéue", "iêuse": "ieuse", "iéues": "ieues",
|
||||
"iềuf": "iêuf", "iềue": "ièue", "iêufe": "ieufe", "ièuef": "ieuef",
|
||||
"iểur": "iêur", "iểue": "iẻue", "iêure": "ieure", "iẻuer": "ieuer",
|
||||
"iễux": "iêux", "iễue": "iẽue", "iêuxe": "ieuxe", "iẽuex": "ieuex",
|
||||
"iệuj": "iêuj", "iệue": "iẹue", "iêuje": "ieuje", "iẹuej": "ieuej",
|
||||
"iếngs": "iêngs", "iếnge": "iénge", "iêngse": "iengse", "iénges": "ienges",
|
||||
"iềngf": "iêngf", "iềnge": "iènge", "iêngfe": "iengfe", "ièngef": "iengef",
|
||||
"iểngr": "iêngr", "iểnge": "iẻnge", "iêngre": "iengre", "iẻnger": "ienger",
|
||||
"iễngx": "iêngx", "iễnge": "iẽnge", "iêngxe": "iengxe", "iẽngex": "iengex",
|
||||
"iệngj": "iêngj", "iệnge": "iẹnge", "iêngje": "iengje", "iẹngej": "iengej",
|
||||
|
||||
"uyens": "uyén", "uyenf": "uyèn", "uyenr": "uyẻn", "uyenx": "uyẽn", "uyenj": "uyẹn",
|
||||
"uyéne": "uyến", "uyène": "uyền", "uyẻne": "uyển", "uyẽne": "uyễn", "uyẹne": "uyện",
|
||||
"uyêns": "uyến", "uyênf": "uyền", "uyênr": "uyển", "uyênx": "uyễn", "uyênj": "uyện",
|
||||
"uyets": "uyét", "uyetf": "uyèt", "uyetr": "uyẻt", "uyetx": "uyẽt", "uyetj": "uyẹt",
|
||||
"uyéte": "uyết", "uyète": "uyềt", "uyẻte": "uyểt", "uyẽte": "uyễt", "uyẹte": "uyệt",
|
||||
"uyêts": "uyết", "uyêtf": "uyềt", "uyêtr": "uyểt", "uyêtx": "uyễt", "uyêtj": "uyệt",
|
||||
|
||||
"uyếns": "uyêns", "uyếne": "uyéne", "uyênse": "uyense", "uyénes": "uyenes",
|
||||
"uyềnf": "uyênf", "uyềne": "uyène", "uyênfe": "uyenfe", "uyènef": "uyenef",
|
||||
"uyểnr": "uyênr", "uyểne": "uyẻne", "uyênre": "uyenre", "uyẻner": "uyener",
|
||||
"uyễnx": "uyênx", "uyễne": "uyẽne", "uyênxe": "uyenxe", "uyẽnex": "uyenex",
|
||||
"uyệnj": "uyênj", "uyệne": "uyẹne", "uyênje": "uyenje", "uyẹnej": "uyenej",
|
||||
"uyếts": "uyêts", "uyếte": "uyéte", "uyêtse": "uyetse", "uyétes": "uyetes",
|
||||
"uyềtf": "uyêtf", "uyềte": "uyète", "uyêtfe": "uyetfe", "uyètef": "uyetef",
|
||||
"uyểtr": "uyêtr", "uyểte": "uyẻte", "uyêtre": "uyetre", "uyẻter": "uyeter",
|
||||
"uyễtx": "uyêtx", "uyễte": "uyẽte", "uyêtxe": "uyetxe", "uyẽtex": "uyetex",
|
||||
"uyệtj": "uyêtj", "uyệte": "uyẹte", "uyêtje": "uyetje", "uyẹtej": "uyetej",
|
||||
|
||||
"uyts": "uýt", "uytj": "uỵt",
|
||||
"uynhs": "uýnh", "uynhf": "uỳnh", "uynhr": "uỷnh", "uynhx": "uỹnh", "uynhj": "uỵnh",
|
||||
|
||||
"uýts": "uyts", "uỵtj": "uytj",
|
||||
"uýnhs": "uynhs", "uỳnhf": "uynhf", "uỷnhr": "uynhr", "uỹnh": "uynhx", "uỵnhj": "uynhj",
|
||||
|
||||
"uits": "uít", "uitj": "uịt",
|
||||
|
||||
"uíts": "uits", "uịtj": "uitj",
|
||||
|
||||
"uos": "úo", "uof": "ùo", "uor": "ủo", "uox": "ũo", "uoj": "ụo",
|
||||
"úoc": "uóc", "ụoc": "uọc",
|
||||
"uocs": "uóc", "uocj": "uọc",
|
||||
"uócw": "ước", "uọcw": "ược",
|
||||
"ươcs": "ước", "ươcj": "ược",
|
||||
"úoi": "uói", "ùoi" : "uòi", "ủoi": "uỏi", "ũoi": "uõi", "ụoi": "uọi",
|
||||
"uois": "uói", "uoif": "uòi", "uoir": "uỏi", "uoix": "uõi", "uoij": "uọi",
|
||||
"uóiw": "ưới", "uòiw": "ười", "uỏiw": "ưởi", "uõiw": "ưỡi", "uọiw": "ượi",
|
||||
"ươis": "ưới", "ươif": "ười", "ươir": "ưởi", "ươix": "ưỡi", "ươij": "ượi",
|
||||
"úom": "uóm", "ùom" : "uòm", "ủom": "uỏm", "ũom": "uõm", "ụom": "uọm",
|
||||
"uoms": "uóm", "uomf": "uòm", "uomr": "uỏm", "uomx": "uõm", "uomj": "uọm",
|
||||
"uómw": "ướm", "uòmw": "ườm", "uỏmw": "ưởm", "uõmw": "ưỡm", "uọmw": "ượm",
|
||||
"ươms": "ướm", "ươmf": "ườm", "ươmr": "ưởm", "ươmx": "ưỡm", "ươmj": "ượm",
|
||||
"úon": "uón", "ùon" : "uòn", "ủon": "uỏn", "ũon": "uõn", "ụon": "uọn",
|
||||
"uons": "uón", "uonf": "uòn", "uonr": "uỏn", "uonx": "uõn", "uonj": "uọn",
|
||||
"uónw": "ướn", "uònw": "ườn", "uỏnw": "ưởn", "uõnw": "ưỡn", "uọnw": "ượn",
|
||||
"ươns": "ướn", "ươnf": "ườn", "ươnr": "ưởn", "ươnx": "ưỡn", "ươnj": "ượn",
|
||||
"úop": "uóp", "ụop": "uọp",
|
||||
"uops": "uóp", "uopj": "uọp",
|
||||
"uópw": "ướp", "uọpw": "ượp",
|
||||
"ươps": "ướp", "ươpj": "ượp",
|
||||
"úot": "uót", "ụot": "uọt",
|
||||
"uots": "uót", "uotj": "uọt",
|
||||
"uótw": "ướt", "uọtw": "ượt",
|
||||
"ươts": "ướt", "ươtj": "ượt",
|
||||
"úou": "uóu", "ùou" : "uòu", "ủou": "uỏu", "ũou": "uõu", "ụou": "uọu",
|
||||
"uous": "uóu", "uouf": "uòu", "uour": "uỏu", "uoux": "uõu", "uouj": "uọu",
|
||||
"uóuw": "ướu", "uòuw": "ườu", "uỏuw": "ưởu", "uõuw": "ưỡu", "uọuw": "ượu",
|
||||
"ươus": "ướu", "ươuf": "ườu", "ươur": "ưởu", "ươux": "ưỡu", "ươuj": "ượu",
|
||||
"úong": "uóng", "ùong" : "uòng", "ủong": "uỏng", "ũong": "uõng", "ụong": "uọng",
|
||||
"uongs": "uóng", "uongf": "uòng", "uongr": "uỏng", "uongx": "uõng", "uongj": "uọng",
|
||||
"uóngw": "ướng", "uòngw": "ường", "uỏngw": "ưởng", "uõngw": "ưỡng", "uọngw": "ượng",
|
||||
"ươngs": "ướng", "ươngf": "ường", "ươngr": "ưởng", "ươngx": "ưỡng", "ươngj": "ượng",
|
||||
|
||||
"úos": "uos", "ùof": "uof", "ủor": "uor", "ũo": "uox", "ụoj": "uoj",
|
||||
"uócs": "uocs", "uọcj": "uocj",
|
||||
"ướcs": "ươcs", "ướcw": "uócw", "ươcsw": "uocsw", "uócws": "uocws",
|
||||
"ượcj": "ươcj", "ượcw": "uọcw", "ươcjw": "uocjw", "uọcwj": "uocwj",
|
||||
"uóis": "uois", "uòif": "uoif", "uỏir": "uoir", "uõix": "uoix", "uọij": "uoij",
|
||||
"ướis": "ươis", "ướiw": "uóiw", "ươisw": "uoisw", "uóiws": "uoiws",
|
||||
"ườif": "ươif", "ườiw": "uòiw", "ươifw": "uoifw", "uòiwf": "uoiwf",
|
||||
"ưởir": "ươir", "ưởiw": "uỏiw", "ươirw": "uoirw", "uỏiwr": "uoiwr",
|
||||
"ưỡix": "ươix", "ưỡiw": "uõiw", "ươixw": "uoixw", "uõiwx": "uoiwx",
|
||||
"ượij": "ươij", "ượiw": "uóiw", "ươijw": "uoijw", "uọiwj": "uoiwj",
|
||||
"uóms": "uoms", "uòmf": "uomf", "uỏmr": "uomr", "uõmx": "uomx", "uọmj": "uomj",
|
||||
"ướms": "ươms", "ướmw": "uómw", "ươmsw": "uomsw", "uómws": "uomws",
|
||||
"ườmf": "ươmf", "ườmw": "uòmw", "ươmfw": "uomfw", "uòmwf": "uomwf",
|
||||
"ưởmr": "ươmr", "ưởmw": "uỏmw", "ươmrw": "uomrw", "uỏmwr": "uomwr",
|
||||
"ưỡmx": "ươmx", "ưỡmw": "uõmw", "ươmxw": "uomxw", "uõmwx": "uomwx",
|
||||
"ượmj": "ươmj", "ượmw": "uómw", "ươmjw": "uomjw", "uọmwj": "uomwj",
|
||||
"uóns": "uons", "uònf": "uonf", "uỏnr": "uonr", "uõnx": "uonx", "uọnj": "uonj",
|
||||
"ướns": "ươns", "ướnw": "uónw", "ươnsw": "uonsw", "uónws": "uonws",
|
||||
"ườnf": "ươnf", "ườnw": "uònw", "ươnfw": "uonfw", "uònwf": "uonwf",
|
||||
"ưởnr": "ươnr", "ưởnw": "uỏnw", "ươnrw": "uonrw", "uỏnwr": "uonwr",
|
||||
"ưỡnx": "ươnx", "ưỡnw": "uõnw", "ươnxw": "uonxw", "uõnwx": "uonwx",
|
||||
"ượnj": "ươnj", "ượnw": "uónw", "ươnjw": "uonjw", "uọnwj": "uonwj",
|
||||
"uóps": "uops", "uọpj": "uopj",
|
||||
"ướps": "ươps", "ướpw": "uópw", "ươpsw": "uopsw", "uópws": "uopws",
|
||||
"ượpj": "ươpj", "ượpw": "uọpw", "ươpjw": "uopjw", "uọpwj": "uopwj",
|
||||
"uóts": "uots", "uọtj": "uotj",
|
||||
"ướts": "ươts", "ướtw": "uótw", "ươtsw": "uotsw", "uótws": "uotws",
|
||||
"ượtj": "ươtj", "ượtw": "uọtw", "ươtjw": "uotjw", "uọtwj": "uotwj",
|
||||
"uóus": "uous", "uòuf": "uouf", "uỏur": "uour", "uõux": "uoux", "uọuj": "uouj",
|
||||
"ướus": "ươus", "ướuw": "uóuw", "ươusw": "uousw", "uóuws": "uouws",
|
||||
"ườuf": "ươuf", "ườuw": "uòuw", "ươufw": "uoufw", "uòuwf": "uouwf",
|
||||
"ưởur": "ươur", "ưởuw": "uỏuw", "ươurw": "uourw", "uỏuwr": "uouwr",
|
||||
"ưỡux": "ươux", "ưỡuw": "uõuw", "ươuxw": "uouxw", "uõuwx": "uouwx",
|
||||
"ượuj": "ươuj", "ượuw": "uóuw", "ươujw": "uoujw", "uọuwj": "uouwj",
|
||||
"uóngs": "uongs", "uòngf": "uongf", "uỏngr": "uongr", "uõngx": "uongx", "uọngj": "uongj",
|
||||
"ướngs": "ươngs", "ướngw": "uóngw", "ươngsw": "uongsw", "uóngws": "uongws",
|
||||
"ườngf": "ươngf", "ườngw": "uòngw", "ươngfw": "uongfw", "uòngwf": "uongwf",
|
||||
"ưởngr": "ươngr", "ưởngw": "uỏngw", "ươngrw": "uongrw", "uỏngwr": "uongwr",
|
||||
"ưỡngx": "ươngx", "ưỡngw": "uõngw", "ươngxw": "uongxw", "uõngwx": "uongwx",
|
||||
"ượngj": "ươngj", "ượngw": "uóngw", "ươngjw": "uongjw", "uọngwj": "uongwj",
|
||||
|
||||
"yes": "ýe", "yef": "ỳe", "yer": "ỷe", "yex": "ỹe", "yej": "ỵe",
|
||||
"ýem": "yém", "ỳem": "yèm", "ỷem": "yẻm", "ỹem": "yẽm", "ỵem": "yẹm",
|
||||
"yems": "yém", "yemf": "yèm", "yemr": "yẻm", "yemx": "yẽm", "yemj": "yẹm",
|
||||
"yêms": "yếm", "yêmf": "yềm", "yêmr": "yểm", "yêmx": "yễm", "yêmj": "yệm",
|
||||
"yéme": "yếm", "yème": "yềm", "yẻme": "yểm", "yẽme": "yễm", "yẹme": "yệm",
|
||||
"ýen": "yén", "ỳen": "yèn", "ỷen": "yẻn", "ỹen": "yẽn", "ỵen": "yẹn",
|
||||
"yens": "yén", "yenf": "yèn", "yenr": "yẻn", "yenx": "yẽn", "yenj": "yẹn",
|
||||
"yêns": "yến", "yênf": "yền", "yênr": "yển", "yênx": "yễn", "yênj": "yện",
|
||||
"yéne": "yến", "yène": "yền", "yẻne": "yển", "yẽne": "yễn", "yẹne": "yện",
|
||||
"ýet": "yét", "ỵet": "yẹt",
|
||||
"yets": "yét", "yetj": "yẹt",
|
||||
"yêts": "yết", "yêtj": "yệt",
|
||||
"yéte": "yết", "yẹte": "yệt",
|
||||
"ýeu": "yéu", "ỳeu": "yèu", "ỷeu": "yẻu", "ỹeu": "yẽu", "ỵeu": "yẹu",
|
||||
"yeus": "yéu", "yeuf": "yèu", "yeur": "yẻu", "yeux": "yẽu", "yeuj": "yẹu",
|
||||
"yêus": "yếu", "yêuf": "yều", "yêur": "yểu", "yêux": "yễu", "yêuj": "yệu",
|
||||
"yéue": "yếu", "yèue": "yều", "yẻue": "yểu", "yẽue": "yễu", "yẹue": "yệu",
|
||||
"ýeng": "yéng", "ỳeng": "yèng", "ỷeng": "yẻng", "ỹeng": "yẽng", "ỵeng": "yẹng",
|
||||
"yengs": "yéng", "yengf": "yèng", "yengr": "yẻng", "yengx": "yẽng", "yengj": "yẹng",
|
||||
"yêngs": "yếng", "yêngf": "yềng", "yêngr": "yểng", "yêngx": "yễng", "yêngj": "yệng",
|
||||
"yénge": "yếng", "yènge": "yềng", "yẻnge": "yểng", "yẽnge": "yễng", "yẹnge": "yệng",
|
||||
|
||||
"ýes": "yes", "ỳef": "yef", "ỷer": "yer", "ỹex": "yex", "ỵej": "yej",
|
||||
"yếms": "yêms", "yếme": "yéme", "yêmse": "yemse", "yémes": "yemes",
|
||||
"yềmf": "yêmf", "yềme": "yème", "yêmfe": "yemfe", "yèmef": "yemef",
|
||||
"yểmr": "yêmr", "yểme": "yẻme", "yêmre": "yemre", "yẻmer": "yemer",
|
||||
"yễmx": "yêmx", "yễme": "yẽme", "yêmxe": "yemxe", "yẽmex": "yemex",
|
||||
"yệmj": "yêmj", "yệme": "yẹme", "yêmje": "yemje", "yẹmej": "yemej",
|
||||
"yếns": "yêns", "yếne": "yéne", "yênse": "yense", "yénes": "yenes",
|
||||
"yềnf": "yênf", "yềne": "yène", "yênfe": "yenfe", "yènef": "yenef",
|
||||
"yểnr": "yênr", "yểne": "yẻne", "yênre": "yenre", "yẻner": "yener",
|
||||
"yễnx": "yênx", "yễne": "yẽne", "yênxe": "yenxe", "yẽnex": "yenex",
|
||||
"yệnj": "yênj", "yệne": "yẹne", "yênje": "yenje", "yẹnej": "yenej",
|
||||
"yếts": "yêts", "yếte": "yéte", "yêtse": "yetse", "yétes": "yetes",
|
||||
"yệtj": "yêtj", "yệte": "yẹte", "yêtje": "yetje", "yẹtej": "yetej",
|
||||
"yếus": "yêus", "yếue": "yéue", "yêuse": "yeuse", "yéues": "yeues",
|
||||
"yềuf": "yêuf", "yềue": "yèue", "yêufe": "yeufe", "yèuef": "yeuef",
|
||||
"yểur": "yêur", "yểue": "yẻue", "yêure": "yeure", "yẻuer": "yeuer",
|
||||
"yễux": "yêux", "yễue": "yẽue", "yêuxe": "yeuxe", "yẽuex": "yeuex",
|
||||
"yệuj": "yêuj", "yệue": "yẹue", "yêuje": "yeuje", "yẹuej": "yeuej",
|
||||
"yếngs": "yêngs", "yếnge": "yénge", "yêngse": "yengse", "yénges": "yenges",
|
||||
"yềngf": "yêngf", "yềnge": "yènge", "yêngfe": "yengfe", "yèngef": "yengef",
|
||||
"yểngr": "yêngr", "yểnge": "yẻnge", "yêngre": "yengre", "yẻnger": "yenger",
|
||||
"yễngx": "yêngx", "yễnge": "yẽnge", "yêngxe": "yengxe", "yẽngex": "yengex",
|
||||
"yệngj": "yêngj", "yệnge": "yẹnge", "yêngje": "yengje", "yẹngej": "yengej"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -135,6 +135,12 @@
|
||||
"authors": [ "mahmoudk1000" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "german2",
|
||||
"label": "German (GBoard)",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "greek",
|
||||
"label": "Ελληνικά",
|
||||
@@ -249,6 +255,20 @@
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian"
|
||||
},
|
||||
{
|
||||
"id": "persian2",
|
||||
"label": "Persian2",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian2"
|
||||
},
|
||||
{
|
||||
"id": "persian3",
|
||||
"label": "Persian3",
|
||||
"authors": [ "SaeID-Rz" ],
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian3"
|
||||
},
|
||||
{
|
||||
"id": "qwerty",
|
||||
"label": "QWERTY",
|
||||
@@ -419,6 +439,18 @@
|
||||
"label": "Persian",
|
||||
"authors": [ "PHELAT" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "persian2",
|
||||
"label": "Persian2",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "persian3",
|
||||
"label": "Persian3",
|
||||
"authors": [ "SaeID-Rz" ],
|
||||
"direction": "rtl"
|
||||
}
|
||||
],
|
||||
"extension": [
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
[
|
||||
[
|
||||
{ "$": "variation_selector",
|
||||
"default": { "$": "case_selector",
|
||||
"lower": { "code": 39, "label": "'", "popup": {
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 34, "label": "\"", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 39, "label": "'"}
|
||||
]
|
||||
} },
|
||||
"default": { "$": "variation_selector",
|
||||
"email": { "code": 64, "label": "@" },
|
||||
"uri": { "code": 47, "label": "/" },
|
||||
"default": { "code": 39, "label": "'", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 34, "label": "\"" }
|
||||
]
|
||||
} },
|
||||
"upper": { "code": 34, "label": "\"", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 39, "label": "'"}
|
||||
]
|
||||
} }
|
||||
},
|
||||
"email": { "code": 64, "label": "@" },
|
||||
"uri": { "code": 47, "label": "/" }
|
||||
}
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 44, "label": ",", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 60, "label": "<" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
} },
|
||||
"upper": { "code": 60, "label": "<", "popup": {
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 60, "label": "<", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 44, "label": "," },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
} },
|
||||
"default": { "code": 44, "label": ",", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 60, "label": "<" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
} }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 46, "label": ".", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 62, "label": ">" }
|
||||
]
|
||||
} },
|
||||
"upper": { "code": 62, "label": ">", "popup": {
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 62, "label": ">", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 46, "label": "." }
|
||||
]
|
||||
} },
|
||||
"default": { "code": 46, "label": ".", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 62, "label": ">" }
|
||||
]
|
||||
} }
|
||||
},
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
|
||||
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
|
||||
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
|
||||
{ "$": "auto_text_key", "code": 1380, "label": "դ" },
|
||||
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
|
||||
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
|
||||
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
|
||||
],
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 228, "label": "ä" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" }
|
||||
]
|
||||
]
|
||||
@@ -48,7 +48,9 @@
|
||||
|
||||
],
|
||||
[
|
||||
|
||||
{ "code": 1600, "label": "kashida", "popup":
|
||||
{ "main": { "code": 8204, "label": "half_space" }
|
||||
} },
|
||||
{ "code": 1574, "label": "ﺋ", "popup": {
|
||||
"main": { "code": 1569, "label": "ء" }
|
||||
} },
|
||||
@@ -58,9 +60,14 @@
|
||||
} },
|
||||
{ "code": 1688, "label": "ژ" },
|
||||
{ "code": 1605, "label": "م" },
|
||||
{ "code": 1567, "label": "؟" },
|
||||
{ "code": 1548, "label": "،" },
|
||||
{ "code": 58, "label": ":" }
|
||||
|
||||
{ "code": 1567, "label": "؟", "popup": {
|
||||
"main": { "code": 63, "label": "?" }
|
||||
} },
|
||||
{ "code": 1548, "label": "،", "popup": {
|
||||
"main": { "code": 1643, "label": "٫" }
|
||||
} },
|
||||
{ "code": 58, "label": ":", "popup": {
|
||||
"main": { "code": 1563, "label": "؛" }
|
||||
} }
|
||||
]
|
||||
]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[
|
||||
[
|
||||
{ "code": 1589, "label": "ص" },
|
||||
{ "code": 1602, "label": "ق" },
|
||||
{ "code": 1601, "label": "ف" },
|
||||
{ "code": 1594, "label": "غ" },
|
||||
{ "code": 1593, "label": "ع" },
|
||||
{ "code": 1607, "label": "ه" },
|
||||
{ "code": 1582, "label": "خ" },
|
||||
{ "code": 1581, "label": "ح" },
|
||||
{ "code": 1580, "label": "ج" },
|
||||
{ "code": 1670, "label": "چ" }
|
||||
],
|
||||
[
|
||||
{ "code": 1588, "label": "ش" },
|
||||
{ "code": 1587, "label": "س" },
|
||||
{ "code": 1740, "label": "ی" },
|
||||
{ "code": 1576, "label": "ب" },
|
||||
{ "code": 1604, "label": "ل" },
|
||||
{ "code": 1575, "label": "ا" },
|
||||
{ "code": 1578, "label": "ت" },
|
||||
{ "code": 1606, "label": "ن" },
|
||||
{ "code": 1605, "label": "م" },
|
||||
{ "code": 1705, "label": "ک" }
|
||||
],
|
||||
[
|
||||
{ "code": 8204, "label": "half_space" },
|
||||
{ "code": 1591, "label": "ط" },
|
||||
{ "code": 1586, "label": "ز" },
|
||||
{ "code": 1585, "label": "ر" },
|
||||
{ "code": 1584, "label": "ذ" },
|
||||
{ "code": 1583, "label": "د" },
|
||||
{ "code": 1608, "label": "و" },
|
||||
{ "code": 1711, "label": "گ" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
[
|
||||
[
|
||||
{ "code": 1590, "label": "ض" },
|
||||
{ "code": 1589, "label": "ص" },
|
||||
{ "code": 1579, "label": "ث" },
|
||||
{ "code": 1602, "label": "ق" },
|
||||
{ "code": 1601, "label": "ف" },
|
||||
{ "code": 1594, "label": "غ" },
|
||||
{ "code": 1593, "label": "ع" },
|
||||
{ "code": 1607, "label": "ه" },
|
||||
{ "code": 1582, "label": "خ" },
|
||||
{ "code": 1581, "label": "ح" },
|
||||
{ "code": 1580, "label": "ج" }
|
||||
],
|
||||
[
|
||||
{ "code": 1588, "label": "ش" },
|
||||
{ "code": 1587, "label": "س" },
|
||||
{ "code": 1740, "label": "ی" },
|
||||
{ "code": 1576, "label": "ب" },
|
||||
{ "code": 1604, "label": "ل" },
|
||||
{ "code": 1575, "label": "ا" },
|
||||
{ "code": 1578, "label": "ت" },
|
||||
{ "code": 1606, "label": "ن" },
|
||||
{ "code": 1605, "label": "م" },
|
||||
{ "code": 1705, "label": "ک" },
|
||||
{ "code": 1711, "label": "گ" }
|
||||
],
|
||||
[
|
||||
{ "code": 1592, "label": "ظ" },
|
||||
{ "code": 1591, "label": "ط" },
|
||||
{ "code": 1586, "label": "ز" },
|
||||
{ "code": 1585, "label": "ر" },
|
||||
{ "code": 1584, "label": "ذ" },
|
||||
{ "code": 1583, "label": "د" },
|
||||
{ "code": 1662, "label": "پ" },
|
||||
{ "code": 1608, "label": "و" },
|
||||
{ "code": 1670, "label": "چ" }
|
||||
]
|
||||
]
|
||||
@@ -8,7 +8,7 @@
|
||||
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
|
||||
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
|
||||
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
|
||||
{ "$": "auto_text_key", "code": 1380, "label": "դ" },
|
||||
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
|
||||
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
|
||||
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
|
||||
],
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
[
|
||||
[
|
||||
{ "code": 1600, "label": "kashida", "popup":
|
||||
{ "main": { "code": 8204, "label": "half_space" }
|
||||
} },
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
[
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "code": -227, "label": "language_switch", "type": "system_gui" },
|
||||
{ "code": -212, "label": "ime_ui_mode_media", "type": "system_gui" },
|
||||
{ "$": "variation_selector",
|
||||
"default": { "code": 1548, "label": "،", "groupId": 1 },
|
||||
"email": { "code": 64, "label": "@", "groupId": 1 },
|
||||
"uri": { "code": 47, "label": "/", "groupId": 1 }
|
||||
},
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 46, "label": ".", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
[
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "$": "variation_selector",
|
||||
"default": { "code": 1548, "label": "،", "groupId": 1 },
|
||||
"email": { "code": 64, "label": "@", "groupId": 1 },
|
||||
"uri": { "code": 47, "label": "/", "groupId": 1 }
|
||||
},
|
||||
{ "code": -227, "label": "language_switch", "type": "system_gui" },
|
||||
{ "code": -212, "label": "ime_ui_mode_media", "type": "system_gui" },
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 46, "label": ".", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -2,9 +2,9 @@
|
||||
"$": "ime.extension.keyboard",
|
||||
"meta": {
|
||||
"id": "org.florisboard.localization",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"title": "Default subtype presets / popup mappings",
|
||||
"description": "Default subptye presets and popup mappings which are always available.",
|
||||
"description": "Default subtype presets and popup mappings which are always available.",
|
||||
"maintainers": [ "patrickgold <patrick@patrickgold.dev>" ],
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
@@ -13,180 +13,62 @@
|
||||
"org.florisboard.currencysets",
|
||||
"org.florisboard.layouts"
|
||||
],
|
||||
"popupMappings": [
|
||||
"punctuationRules": [
|
||||
{
|
||||
"id": "default",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "ar",
|
||||
"authors": [ "HeiWiper" ]
|
||||
},
|
||||
{
|
||||
"id": "bg",
|
||||
"authors": [ "iorvethe" ]
|
||||
},
|
||||
{
|
||||
"id": "ca",
|
||||
"authors": [ "mikelloc" ]
|
||||
},
|
||||
{
|
||||
"id": "ckb",
|
||||
"authors": [ "GoRaN" ]
|
||||
},
|
||||
{
|
||||
"id": "cs",
|
||||
"authors": [ "stefan-misik" ]
|
||||
},
|
||||
{
|
||||
"id": "da",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "de",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "de-DE-neobone",
|
||||
"authors": [ "ostrya" ]
|
||||
},
|
||||
{
|
||||
"id": "el",
|
||||
"authors": [ "tsiflimagas" ]
|
||||
},
|
||||
{
|
||||
"id": "en",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "eo",
|
||||
"authors": [ "jeremiah-miller" ]
|
||||
},
|
||||
{
|
||||
"id": "es",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "fa",
|
||||
"authors": [ "PHELAT" ]
|
||||
},
|
||||
{
|
||||
"id": "fi",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "fo",
|
||||
"authors": [ "BinFlush" ]
|
||||
},
|
||||
{
|
||||
"id": "fr",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "hr",
|
||||
"authors": [ "hedidnothingwrong" ]
|
||||
},
|
||||
{
|
||||
"id": "hu",
|
||||
"authors": [ "zoli111, gabik65" ]
|
||||
},
|
||||
{
|
||||
"id": "hy",
|
||||
"authors": [ "PJTSearch" ]
|
||||
},
|
||||
{
|
||||
"id": "is",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "it",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "iw",
|
||||
"authors": [ "Antony" ]
|
||||
},
|
||||
{
|
||||
"id": "ja-JP-jis",
|
||||
"authors": [ "waelwindows" ]
|
||||
},
|
||||
{
|
||||
"id": "ko",
|
||||
"authors": [ "patrickgold", "Hayleia" ]
|
||||
},
|
||||
{
|
||||
"id": "ku",
|
||||
"authors": [ "GoRaN" ]
|
||||
},
|
||||
{
|
||||
"id": "lt",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "lv",
|
||||
"authors": [ "patrickgold", "eandersons" ]
|
||||
},
|
||||
{
|
||||
"id": "nb",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "nn",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "pl",
|
||||
"authors": [ "Mikołaj Biel" ]
|
||||
},
|
||||
{
|
||||
"id": "pt",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "pt-BR",
|
||||
"authors": [ "rickym7" ]
|
||||
},
|
||||
{
|
||||
"id": "ro",
|
||||
"authors": [ "bertin0" ]
|
||||
},
|
||||
{
|
||||
"id": "ru",
|
||||
"authors": [ "williamtheaker", "33kk" ]
|
||||
},
|
||||
{
|
||||
"id": "rue",
|
||||
"authors": [ "svvvst" ]
|
||||
},
|
||||
{
|
||||
"id": "sk",
|
||||
"authors": [ "stefan-misik", "majso" ]
|
||||
},
|
||||
{
|
||||
"id": "sr",
|
||||
"authors": [ "hedidnothingwrong", "GrbavaCigla" ]
|
||||
},
|
||||
{
|
||||
"id": "sv",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "tr",
|
||||
"authors": [ "kisekinopureya", "patrickgold", "dvrnynr" ]
|
||||
},
|
||||
{
|
||||
"id": "uk",
|
||||
"authors": [ "williamtheaker", "33kk" ]
|
||||
},
|
||||
{
|
||||
"id": "ur-PK",
|
||||
"authors": [ "mubashir-rehman", "mirfatif" ]
|
||||
},
|
||||
{
|
||||
"id": "vi-VN",
|
||||
"authors": [ "patrickgold", "Hayleia" ]
|
||||
"label": "Default",
|
||||
"symbolsPrecedingSpace": ".*[.,;:!?‽&%)\\]}»©®™\\p{L}0-9]",
|
||||
"symbolsFollowingSpace": "[\\p{L}0-9].*"
|
||||
}
|
||||
],
|
||||
"popupMappings": [
|
||||
{ "id": "default", "authors": [ "patrickgold" ] },
|
||||
{ "id": "ar", "authors": [ "HeiWiper" ] },
|
||||
{ "id": "bg", "authors": [ "iorvethe" ] },
|
||||
{ "id": "ca", "authors": [ "mikelloc" ] },
|
||||
{ "id": "ckb", "authors": [ "GoRaN" ] },
|
||||
{ "id": "cs", "authors": [ "stefan-misik" ] },
|
||||
{ "id": "da", "authors": [ "patrickgold" ] },
|
||||
{ "id": "de", "authors": [ "patrickgold" ] },
|
||||
{ "id": "de-DE-neobone", "authors": [ "ostrya" ] },
|
||||
{ "id": "el", "authors": [ "tsiflimagas" ] },
|
||||
{ "id": "en", "authors": [ "patrickgold" ] },
|
||||
{ "id": "eo", "authors": [ "jeremiah-miller" ] },
|
||||
{ "id": "es", "authors": [ "patrickgold" ] },
|
||||
{ "id": "fa", "authors": [ "PHELAT" ] },
|
||||
{ "id": "fa2", "authors": [ "M-Koushan" ] },
|
||||
{ "id": "fa3", "authors": [ "SaeID-Rz" ] },
|
||||
{ "id": "fi", "authors": [ "patrickgold" ] },
|
||||
{ "id": "fo", "authors": [ "BinFlush" ] },
|
||||
{ "id": "fr", "authors": [ "patrickgold" ] },
|
||||
{ "id": "hr", "authors": [ "hedidnothingwrong" ] },
|
||||
{ "id": "hu", "authors": [ "zoli111, gabik65" ] },
|
||||
{ "id": "hy", "authors": [ "PJTSearch" ] },
|
||||
{ "id": "is", "authors": [ "patrickgold" ] },
|
||||
{ "id": "it", "authors": [ "patrickgold" ] },
|
||||
{ "id": "iw", "authors": [ "Antony" ] },
|
||||
{ "id": "ja-JP-jis", "authors": [ "waelwindows" ] },
|
||||
{ "id": "ko", "authors": [ "patrickgold", "Hayleia" ] },
|
||||
{ "id": "ku", "authors": [ "GoRaN" ] },
|
||||
{ "id": "lt", "authors": [ "patrickgold" ] },
|
||||
{ "id": "lv", "authors": [ "patrickgold", "eandersons" ] },
|
||||
{ "id": "nb", "authors": [ "patrickgold" ] },
|
||||
{ "id": "nn", "authors": [ "patrickgold" ] },
|
||||
{ "id": "pl", "authors": [ "Mikołaj Biel" ] },
|
||||
{ "id": "pt", "authors": [ "patrickgold" ] },
|
||||
{ "id": "pt-BR", "authors": [ "rickym7" ] },
|
||||
{ "id": "ro", "authors": [ "bertin0" ] },
|
||||
{ "id": "ru", "authors": [ "williamtheaker", "33kk" ] },
|
||||
{ "id": "rue", "authors": [ "svvvst" ] },
|
||||
{ "id": "sk", "authors": [ "stefan-misik", "majso" ] },
|
||||
{ "id": "sr", "authors": [ "hedidnothingwrong", "GrbavaCigla" ] },
|
||||
{ "id": "sv", "authors": [ "patrickgold" ] },
|
||||
{ "id": "tr", "authors": [ "kisekinopureya", "patrickgold", "dvrnynr" ] },
|
||||
{ "id": "uk", "authors": [ "williamtheaker", "33kk", "honsiorovskyi" ] },
|
||||
{ "id": "uk-cyr-ext", "authors": [ "williamtheaker", "33kk", "honsiorovskyi" ] },
|
||||
{ "id": "ur-PK", "authors": [ "mubashir-rehman", "mirfatif" ] },
|
||||
{ "id": "vi-VN", "authors": [ "patrickgold", "Hayleia" ] }
|
||||
],
|
||||
"subtypePresets": [
|
||||
{
|
||||
"languageTag": "en-US",
|
||||
@@ -427,6 +309,30 @@
|
||||
"numericRow": "org.florisboard.layouts:persian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "fa-FA",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:rial",
|
||||
"popupMapping": "org.florisboard.localization:fa2",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:persian2",
|
||||
"symbols": "org.florisboard.layouts:persian",
|
||||
"symbols2": "org.florisboard.layouts:persian",
|
||||
"numericRow": "org.florisboard.layouts:persian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "fa-FA",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:rial",
|
||||
"popupMapping": "org.florisboard.localization:fa3",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:persian3",
|
||||
"symbols": "org.florisboard.layouts:persian",
|
||||
"symbols2": "org.florisboard.layouts:persian",
|
||||
"numericRow": "org.florisboard.layouts:western_arabic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ar",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -693,7 +599,7 @@
|
||||
},
|
||||
{
|
||||
"languageTag": "vi-VN",
|
||||
"composer": "org.florisboard.composers:basic-telex",
|
||||
"composer": "org.florisboard.composers:telex",
|
||||
"currencySet": "org.florisboard.currencysets:vietnamese_dong",
|
||||
"popupMapping": "org.florisboard.localization:vi-VN",
|
||||
"preferred": {
|
||||
|
||||
@@ -11,16 +11,18 @@
|
||||
]
|
||||
},
|
||||
"ی": {
|
||||
"main": { "code": 1610, "label": "ي" },
|
||||
"relevant": [
|
||||
{ "code": 1746, "label": "ے" },
|
||||
{ "code": 1741, "label": "ۍ" },
|
||||
{ "code": 1744, "label": "ې" },
|
||||
{ "code": 1610, "label": "ي" },
|
||||
{ "code": 1597, "label": "ؽ" }
|
||||
{ "code": 1744, "label": "ې" }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
"ێ": {
|
||||
"main": { "code": 1597, "label": "ؽ" }
|
||||
},
|
||||
|
||||
"ﺋ": {
|
||||
"relevant": [
|
||||
{ "code": 65163, "label": "ﺋ" },
|
||||
@@ -118,19 +120,23 @@
|
||||
"~right": {
|
||||
"main": { "code": 1567, "label": "؟" },
|
||||
"relevant": [
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 40, "label": "(" },
|
||||
{ "code": 41, "label": ")" },
|
||||
{ "code": 171, "label": "«" },
|
||||
{ "code": 187, "label": "»" },
|
||||
{ "code": 60, "label": "<" },
|
||||
{ "code": 62, "label": ">" },
|
||||
{ "code": 1642, "label": "٪" },
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 42, "label": "*" },
|
||||
{ "code": 1563, "label": "؛" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 44, "label": "," },
|
||||
{ "code": 1549, "label": "؍" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 95, "label": "_" },
|
||||
{ "code": 1600, "label": "▬" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 1548, "label": "،" }
|
||||
{ "code": 1563, "label": "؛" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 1549, "label": "؍" },
|
||||
{ "code": 1643, "label": "٫" },
|
||||
{ "code": 1548, "label": "،" },
|
||||
{ "code": 33, "label": "!" }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"all": {
|
||||
"ص": {
|
||||
"relevant": [
|
||||
{ "code": 1590, "label": "ض" }
|
||||
]
|
||||
},
|
||||
"half_space": {
|
||||
"relevant": [
|
||||
{ "code": 1622, "label": "ٖ" },
|
||||
{ "code": 1648, "label": "ٰ" },
|
||||
{ "code": 1619, "label": "ٓ" },
|
||||
{ "code": 1615, "label": "ُ" },
|
||||
{ "code": 1616, "label": "ِ" },
|
||||
{ "code": 1614, "label": "َ" },
|
||||
{ "code": 1600, "label": "ـ" },
|
||||
{ "code": 1621, "label": "ٕ" },
|
||||
{ "code": 1618, "label": "ْ" },
|
||||
{ "code": 1617, "label": "ّ" },
|
||||
{ "code": 1612, "label": "ٌ" },
|
||||
{ "code": 1613, "label": "ٍ" },
|
||||
{ "code": 1620, "label": "ٔ" }
|
||||
]
|
||||
},
|
||||
"ی": {
|
||||
"relevant": [
|
||||
{ "code": 1574, "label": "ئ" },
|
||||
{ "code": 1610, "label": "ي" },
|
||||
{ "code": 1746, "label": "ے" }
|
||||
]
|
||||
},
|
||||
"ا": {
|
||||
"main": { "code": 1570, "label": "آ"},
|
||||
"relevant": [
|
||||
{ "code": 1649, "label": "ٱ" },
|
||||
{ "code": 1569, "label": "ء" },
|
||||
{ "code": 1571, "label": "أ" },
|
||||
{ "code": 1573, "label": "إ" }
|
||||
]
|
||||
},
|
||||
"ه": {
|
||||
"relevant": [
|
||||
{ "code": 1729, "label": "ہ" },
|
||||
{ "code": 1728, "label": "ۀ" },
|
||||
{ "code": 1726, "label": "ھ" }
|
||||
]
|
||||
},
|
||||
"ت": {
|
||||
"relevant": [
|
||||
{ "code": 1579, "label": "ث" }
|
||||
]
|
||||
},
|
||||
"ک": {
|
||||
"relevant": [
|
||||
{ "code": 1706, "label": "ڪ"}
|
||||
]
|
||||
},
|
||||
"ط": {
|
||||
"relevant": [
|
||||
{ "code": 1592, "label": "ظ" }
|
||||
]
|
||||
},
|
||||
"ز": {
|
||||
"relevant": [
|
||||
{ "code": 1688, "label": "ژ" }
|
||||
]
|
||||
},
|
||||
"و": {
|
||||
"relevant": [
|
||||
{ "code": 1572, "label": "ؤ" }
|
||||
]
|
||||
},
|
||||
"گ": {
|
||||
"relevant": [
|
||||
{ "code": 1662, "label": "پ" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 1567, "label": "؟"},
|
||||
"relevant": [
|
||||
{ "code": 1563, "label": "؛" },
|
||||
{ "code": 58, "label": ":"},
|
||||
{ "code": 33, "label": "!" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".com" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"all": {
|
||||
"ی": {
|
||||
"main": { "code": 1574, "label": "ئ" },
|
||||
"relevant": [
|
||||
{ "code": 1610, "label": "ي" },
|
||||
{ "code": 1746, "label": "ے" }
|
||||
]
|
||||
},
|
||||
"ا": {
|
||||
"main": { "code": 1570, "label": "آ" },
|
||||
"relevant": [
|
||||
{ "code": 1649, "label": "ٱ" },
|
||||
{ "code": 1569, "label": "ء" },
|
||||
{ "code": 1571, "label": "أ" },
|
||||
{ "code": 1573, "label": "إ" }
|
||||
]
|
||||
},
|
||||
"ه": {
|
||||
"relevant": [
|
||||
{ "code": 1729, "label": "ہ" },
|
||||
{ "code": 1728, "label": "ۀ" },
|
||||
{ "code": 1726, "label": "ھ" }
|
||||
]
|
||||
},
|
||||
"ت": {
|
||||
"relevant": [
|
||||
{ "code": 1577, "label": "ة" }
|
||||
]
|
||||
},
|
||||
"ک": {
|
||||
"relevant": [
|
||||
{ "code": 1706, "label": "ڪ"}
|
||||
]
|
||||
},
|
||||
"ز": {
|
||||
"relevant": [
|
||||
{ "code": 1688, "label": "ژ" }
|
||||
]
|
||||
},
|
||||
"و": {
|
||||
"relevant": [
|
||||
{ "code": 1572, "label": "ؤ" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 1611, "label": "ً" },
|
||||
"relevant": [
|
||||
{ "code": 1615, "label": "ُ" },
|
||||
{ "code": 1616, "label": "ِ" },
|
||||
{ "code": 1614, "label": "َ" },
|
||||
{ "code": 1617, "label": "ّ" },
|
||||
{ "code": 1620, "label": "ٔ" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".com" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"all": {
|
||||
"е": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1105, "label": "ё" }
|
||||
]
|
||||
},
|
||||
"у": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1118, "label": "ў" }
|
||||
]
|
||||
},
|
||||
"г": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1169, "label": "ґ" }
|
||||
]
|
||||
},
|
||||
"і": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1111, "label": "ї" },
|
||||
{ "$": "auto_text_key", "code": 1099, "label": "ы" }
|
||||
]
|
||||
},
|
||||
"є": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 8212, "label": "—" },
|
||||
{ "$": "auto_text_key", "code": 1101, "label": "э" }
|
||||
]
|
||||
},
|
||||
"ь": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 700, "label": "ʼ" },
|
||||
{ "$": "auto_text_key", "code": 39, "label": "'" },
|
||||
{ "$": "auto_text_key", "code": 1098, "label": "ъ" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".ua" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,26 @@
|
||||
{
|
||||
"all": {
|
||||
"г": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1169, "label": "ґ" }
|
||||
]
|
||||
},
|
||||
"і": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1111, "label": "ї" }
|
||||
]
|
||||
},
|
||||
"є": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 8212, "label": "—" }
|
||||
]
|
||||
},
|
||||
"ь": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 700, "label": "ʼ" },
|
||||
{ "$": "auto_text_key", "code": 39, "label": "'" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
@@ -37,7 +53,6 @@
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".ua" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
[
|
||||
")",
|
||||
"}",
|
||||
"]",
|
||||
">",
|
||||
|
||||
"&",
|
||||
|
||||
".",
|
||||
",",
|
||||
"?",
|
||||
"!",
|
||||
";",
|
||||
":"
|
||||
]
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_black",
|
||||
"label": "Floris Black",
|
||||
"authors": [ "serebit" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#388E3C",
|
||||
"colorPrimaryDark": "#306D32",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#EEEEEE"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#000000"
|
||||
},
|
||||
"key": {
|
||||
"background": "#212121",
|
||||
"backgroundPressed": "#3D3D3D",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "true"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#000000",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#424242",
|
||||
"backgroundActive": "#707070",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#7800BF",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "@key/background",
|
||||
"foreground": "@key/foreground"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#20388E3C"}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_black_borderless",
|
||||
"label": "Floris Black Borderless",
|
||||
"authors": [ "serebit" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#388E3C",
|
||||
"colorPrimaryDark": "#306D32",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#EEEEEE"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#000000"
|
||||
},
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"backgroundPressed": "#7F616161",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "false"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"key:space": {
|
||||
"background": "#46616161"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#000000",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#363636",
|
||||
"backgroundActive": "#5F5F5F",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#7800BF",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "#212121",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#20388E3C"}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_day",
|
||||
"label": "Floris Day",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": false,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "true",
|
||||
"semiTransparentColor": "#20000000",
|
||||
"textColor": "#000000"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#E0E0E0"
|
||||
},
|
||||
"key": {
|
||||
"background": "#FFFFFF",
|
||||
"backgroundPressed": "#F5F5F5",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "true"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#757575"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#E8F5E9",
|
||||
"foreground": "#424242"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#EEEEEE",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "@key/background",
|
||||
"foreground": "@key/foreground"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#E8E8E8",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_day_borderless",
|
||||
"label": "Floris Day Borderless",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": false,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "true",
|
||||
"semiTransparentColor": "#20000000",
|
||||
"textColor": "#000000"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#E0E0E0"
|
||||
},
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"backgroundPressed": "#7FF5F5F5",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "false"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"key:space": {
|
||||
"background": "#7FF5F5F5",
|
||||
"backgroundPressed": "#FFF5F5F5"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#757575"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#E8F5E9",
|
||||
"foreground": "#424242"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#EEEEEE",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "#FFFFFF",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#E8E8E8",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_night",
|
||||
"label": "Floris Night",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#FFFFFF"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#212121"
|
||||
},
|
||||
"key": {
|
||||
"background": "#424242",
|
||||
"backgroundPressed": "#616161",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "true"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#1B5E20",
|
||||
"foreground": "#EEEEEE"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#757575",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "@key/background",
|
||||
"foreground": "@key/foreground"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_night_borderless",
|
||||
"label": "Floris Night Borderless",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#FFFFFF"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#212121"
|
||||
},
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"backgroundPressed": "#7F616161",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "false"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"key:space": {
|
||||
"background": "#2F616161",
|
||||
"backgroundPressed": "#7F616161"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#1B5E20",
|
||||
"foreground": "#EEEEEE"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#757575",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "#424242",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,14 @@
|
||||
"isBorderless": false,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_day_borderless",
|
||||
"label": "Floris Day (Borderless)",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNight": false,
|
||||
"isBorderless": true,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_night",
|
||||
"label": "Floris Night",
|
||||
@@ -24,6 +32,30 @@
|
||||
"isNight": true,
|
||||
"isBorderless": false,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_night_borderless",
|
||||
"label": "Floris Night (Borderless)",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNight": true,
|
||||
"isBorderless": true,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_pure_night",
|
||||
"label": "Floris Pure Night",
|
||||
"authors": [ "serebit" ],
|
||||
"isNight": true,
|
||||
"isBorderless": false,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_pure_night_borderless",
|
||||
"label": "Floris Pure Night (Borderless)",
|
||||
"authors": [ "serebit" ],
|
||||
"isNight": true,
|
||||
"isBorderless": true,
|
||||
"isMaterialYouAware": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface-variant)",
|
||||
@@ -39,7 +39,7 @@
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][mode={m:capslock}]": {
|
||||
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
@@ -56,8 +56,8 @@
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
@@ -67,8 +67,8 @@
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "circle()"
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
@@ -127,15 +127,15 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
@@ -152,8 +152,8 @@
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
@@ -162,6 +162,23 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
"--secondary": "#ff9800",
|
||||
"--secondary-variant": "#e65100",
|
||||
"--background": "#e0e0e0",
|
||||
"--surface": "#f0f0f0",
|
||||
"--surface-variant": "#ffffff",
|
||||
|
||||
"--on-background": "#121212",
|
||||
"--on-surface": "#000000",
|
||||
"--on-surface-variant": "#5f5f5f",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#e8f5e9",
|
||||
"foreground": "#424242"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,8 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface-variant)",
|
||||
@@ -39,7 +39,7 @@
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][mode={m:capslock}]": {
|
||||
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
@@ -56,8 +56,8 @@
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
@@ -67,8 +67,8 @@
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "circle()"
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
@@ -127,15 +127,15 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
@@ -152,8 +152,8 @@
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
@@ -162,6 +162,23 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
"--secondary": "#f57c00",
|
||||
"--secondary-variant": "#e65100",
|
||||
"--background": "#212121",
|
||||
"--surface": "#424242",
|
||||
"--surface-variant": "#616161",
|
||||
|
||||
"--on-background": "#dcdcdc",
|
||||
"--on-surface": "#ffffff",
|
||||
"--on-surface-variant": "#a0a0a0",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#1b5e20",
|
||||
"foreground": "#eeeeee"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#388e3c",
|
||||
"--primary-variant": "#306d32",
|
||||
"--secondary": "#ff9800",
|
||||
"--secondary-variant": "#804c00",
|
||||
"--background": "#000000",
|
||||
"--surface": "#212121",
|
||||
"--surface-variant": "#3d3d3d",
|
||||
|
||||
"--on-background": "#eeeeee",
|
||||
"--on-surface": "#eeeeee",
|
||||
"--on-surface-variant": "#ffffff73",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#424242",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#707070",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary-variant)",
|
||||
"border-width": "1dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary-variant)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#000000",
|
||||
"foreground": "#eeeeee"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#388e3c",
|
||||
"--primary-variant": "#306d32",
|
||||
"--secondary": "#ff9800",
|
||||
"--secondary-variant": "#804c00",
|
||||
"--background": "#000000",
|
||||
"--surface": "#212121",
|
||||
"--surface-variant": "#3d3d3d",
|
||||
|
||||
"--on-background": "#eeeeee",
|
||||
"--on-surface": "#eeeeee",
|
||||
"--on-surface-variant": "#ffffff73",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "#6161617f",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "#61616146",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#363636",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#5F5F5F",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary-variant)",
|
||||
"border-width": "1dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary-variant)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#000000",
|
||||
"foreground": "#eeeeee"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 16 KiB |
BIN
app/src/main/ic_app_icon_stable-playstore.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.ui.settings.theme
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.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.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisChip
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisDropdownMenu
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisHyperlinkText
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.common.kotlin.curlyFormat
|
||||
import dev.patrickgold.florisboard.ime.nlp.NATIVE_NULLPTR
|
||||
import dev.patrickgold.florisboard.ime.text.key.InputMode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUiSpec
|
||||
import dev.patrickgold.florisboard.snygg.SnyggLevel
|
||||
import dev.patrickgold.florisboard.snygg.SnyggRule
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||
internal val SnyggEmptyRuleForAdding = SnyggRule(element = "- select -")
|
||||
|
||||
@Composable
|
||||
internal fun EditRuleDialog(
|
||||
initRule: SnyggRule,
|
||||
level: SnyggLevel,
|
||||
onConfirmRule: (oldRule: SnyggRule, newRule: SnyggRule) -> Boolean,
|
||||
onDeleteRule: (rule: SnyggRule) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val isAddRuleDialog = initRule == SnyggEmptyRuleForAdding
|
||||
var showSelectAsError by rememberSaveable { mutableStateOf(false) }
|
||||
var showAlreadyExistsError by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val possibleElementNames = remember {
|
||||
listOf(SnyggEmptyRuleForAdding.element) + FlorisImeUiSpec.elements.keys
|
||||
}
|
||||
val possibleElementLabels = possibleElementNames.map { translateElementName(it, level) ?: it }
|
||||
var elementsExpanded by remember { mutableStateOf(false) }
|
||||
var elementsSelectedIndex by rememberSaveable {
|
||||
val index = possibleElementNames.indexOf(initRule.element).coerceIn(possibleElementNames.indices)
|
||||
mutableStateOf(index)
|
||||
}
|
||||
|
||||
val codes = rememberSaveable(saver = IntListSaver) { initRule.codes.toMutableStateList() }
|
||||
var editCodeDialogValue by rememberSaveable { mutableStateOf<Int?>(null) }
|
||||
val groups = rememberSaveable(saver = IntListSaver) { initRule.groups.toMutableStateList() }
|
||||
var modeNormal by rememberSaveable { mutableStateOf(initRule.modes.contains(InputMode.NORMAL.value)) }
|
||||
var modeShiftLock by rememberSaveable { mutableStateOf(initRule.modes.contains(InputMode.SHIFT_LOCK.value)) }
|
||||
var modeCapsLock by rememberSaveable { mutableStateOf(initRule.modes.contains(InputMode.CAPS_LOCK.value)) }
|
||||
var pressedSelector by rememberSaveable { mutableStateOf(initRule.pressedSelector) }
|
||||
var focusSelector by rememberSaveable { mutableStateOf(initRule.focusSelector) }
|
||||
var disabledSelector by rememberSaveable { mutableStateOf(initRule.disabledSelector) }
|
||||
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(if (isAddRuleDialog) {
|
||||
R.string.settings__theme_editor__add_rule
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_rule
|
||||
}),
|
||||
confirmLabel = stringRes(if (isAddRuleDialog) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}),
|
||||
onConfirm = {
|
||||
if (isAddRuleDialog && elementsSelectedIndex == 0) {
|
||||
showSelectAsError = true
|
||||
} else {
|
||||
val newRule = SnyggRule(
|
||||
element = possibleElementNames[elementsSelectedIndex],
|
||||
codes = codes.toList(),
|
||||
groups = groups.toList(),
|
||||
modes = buildList {
|
||||
if (modeNormal) { add(InputMode.NORMAL.value) }
|
||||
if (modeShiftLock) { add(InputMode.SHIFT_LOCK.value) }
|
||||
if (modeCapsLock) { add(InputMode.CAPS_LOCK.value) }
|
||||
},
|
||||
pressedSelector = pressedSelector,
|
||||
focusSelector = focusSelector,
|
||||
disabledSelector = disabledSelector,
|
||||
)
|
||||
if (!onConfirmRule(initRule, newRule)) {
|
||||
showAlreadyExistsError = true
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissLabel = stringRes(R.string.action__cancel),
|
||||
onDismiss = onDismiss,
|
||||
neutralLabel = if (!isAddRuleDialog) {
|
||||
stringRes(R.string.action__delete)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error),
|
||||
onNeutral = { onDeleteRule(initRule) },
|
||||
) {
|
||||
Column {
|
||||
AnimatedVisibility(visible = showAlreadyExistsError) {
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 16.dp),
|
||||
text = stringRes(R.string.settings__theme_editor__rule_already_exists),
|
||||
color = MaterialTheme.colors.error,
|
||||
)
|
||||
}
|
||||
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_element)) {
|
||||
FlorisDropdownMenu(
|
||||
items = possibleElementLabels,
|
||||
expanded = elementsExpanded,
|
||||
enabled = isAddRuleDialog,
|
||||
selectedIndex = elementsSelectedIndex,
|
||||
isError = showSelectAsError && elementsSelectedIndex == 0,
|
||||
onSelectItem = { elementsSelectedIndex = it },
|
||||
onExpandRequest = { elementsExpanded = true },
|
||||
onDismissRequest = { elementsExpanded = false },
|
||||
)
|
||||
}
|
||||
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_selectors)) {
|
||||
Row(modifier = Modifier.florisHorizontalScroll()) {
|
||||
FlorisChip(
|
||||
onClick = { pressedSelector = !pressedSelector },
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.PRESSED_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__pressed)
|
||||
},
|
||||
color = if (pressedSelector) MaterialTheme.colors.primaryVariant else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { focusSelector = !focusSelector },
|
||||
modifier = Modifier.padding( end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.FOCUS_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__focus)
|
||||
},
|
||||
color = if (focusSelector) MaterialTheme.colors.primaryVariant else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { disabledSelector = !disabledSelector },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.DISABLED_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__disabled)
|
||||
},
|
||||
color = if (disabledSelector) MaterialTheme.colors.primaryVariant else Color.Unspecified,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DialogProperty(
|
||||
text = stringRes(R.string.settings__theme_editor__rule_codes),
|
||||
trailingIconTitle = {
|
||||
FlorisIconButton(
|
||||
onClick = { editCodeDialogValue = NATIVE_NULLPTR },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = painterResource(R.drawable.ic_add),
|
||||
)
|
||||
},
|
||||
) {
|
||||
if (codes.isEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
text = stringRes(R.string.settings__theme_editor__no_codes_defined),
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
}
|
||||
FlowRow {
|
||||
for (code in codes) {
|
||||
FlorisChip(
|
||||
onClick = { editCodeDialogValue = code },
|
||||
text = code.toString(),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_modes)) {
|
||||
Row(modifier = Modifier.florisHorizontalScroll()) {
|
||||
FlorisChip(
|
||||
onClick = { modeNormal = !modeNormal },
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember { "m:${InputMode.NORMAL.toString().lowercase()}" }
|
||||
else -> stringRes(R.string.enum__input_mode__normal)
|
||||
},
|
||||
color = if (modeNormal) MaterialTheme.colors.primaryVariant else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { modeShiftLock = !modeShiftLock },
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember { "m:${InputMode.SHIFT_LOCK.toString().lowercase()}" }
|
||||
else -> stringRes(R.string.enum__input_mode__shift_lock)
|
||||
},
|
||||
color = if (modeShiftLock) MaterialTheme.colors.primaryVariant else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { modeCapsLock = !modeCapsLock },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember { "m:${InputMode.CAPS_LOCK.toString().lowercase()}" }
|
||||
else -> stringRes(R.string.enum__input_mode__caps_lock)
|
||||
},
|
||||
color = if (modeCapsLock) MaterialTheme.colors.primaryVariant else Color.Unspecified,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val initCodeValue = editCodeDialogValue
|
||||
if (initCodeValue != null) {
|
||||
var inputCodeString by rememberSaveable(initCodeValue) { mutableStateOf(initCodeValue.toString()) }
|
||||
var showKeyCodesHelp by rememberSaveable(initCodeValue) { mutableStateOf(false) }
|
||||
var showError by rememberSaveable(initCodeValue) { mutableStateOf(false) }
|
||||
var errorId by rememberSaveable(initCodeValue) { mutableStateOf(NATIVE_NULLPTR) }
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(if (initCodeValue == NATIVE_NULLPTR) {
|
||||
R.string.settings__theme_editor__add_code
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_code
|
||||
}),
|
||||
confirmLabel = stringRes(if (initCodeValue == NATIVE_NULLPTR) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}),
|
||||
onConfirm = {
|
||||
val code = inputCodeString.trim().toIntOrNull(radix = 10)
|
||||
when {
|
||||
code == null || (code !in KeyCode.Spec.CHARACTERS && code !in KeyCode.Spec.INTERNAL) -> {
|
||||
errorId = R.string.settings__theme_editor__code_invalid
|
||||
showError = true
|
||||
}
|
||||
code == initCodeValue -> {
|
||||
editCodeDialogValue = null
|
||||
}
|
||||
codes.contains(code) -> {
|
||||
errorId = R.string.settings__theme_editor__code_already_exists
|
||||
showError = true
|
||||
}
|
||||
else -> {
|
||||
if (initCodeValue != NATIVE_NULLPTR) {
|
||||
codes.remove(initCodeValue)
|
||||
}
|
||||
codes.add(code)
|
||||
editCodeDialogValue = null
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissLabel = stringRes(R.string.action__cancel),
|
||||
onDismiss = {
|
||||
editCodeDialogValue = null
|
||||
},
|
||||
neutralLabel = if (initCodeValue != NATIVE_NULLPTR) {
|
||||
stringRes(R.string.action__delete)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error),
|
||||
onNeutral = {
|
||||
codes.remove(initCodeValue)
|
||||
editCodeDialogValue = null
|
||||
},
|
||||
trailingIconTitle = {
|
||||
FlorisIconButton(
|
||||
onClick = { showKeyCodesHelp = !showKeyCodesHelp },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = painterResource(R.drawable.ic_help_outline),
|
||||
)
|
||||
},
|
||||
) {
|
||||
Column {
|
||||
AnimatedVisibility(visible = showKeyCodesHelp) {
|
||||
Column(modifier = Modifier.padding(bottom = 16.dp)) {
|
||||
Text(text = stringRes(R.string.settings__theme_editor__code_help_text))
|
||||
FlorisHyperlinkText(
|
||||
text = "Characters (unicode-table.com)",
|
||||
url = stringRes(R.string.florisboard__character_key_codes_url),
|
||||
)
|
||||
FlorisHyperlinkText(
|
||||
text = "Internal (github.com)",
|
||||
url = stringRes(R.string.florisboard__internal_key_codes_url),
|
||||
)
|
||||
}
|
||||
}
|
||||
FlorisOutlinedTextField(
|
||||
value = inputCodeString,
|
||||
onValueChange = { v ->
|
||||
inputCodeString = v
|
||||
showError = false
|
||||
},
|
||||
isError = showError,
|
||||
singleLine = true,
|
||||
)
|
||||
AnimatedVisibility(visible = showError) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
text = stringRes(errorId).curlyFormat(
|
||||
"c_min" to KeyCode.Spec.CHARACTERS_MIN,
|
||||
"c_max" to KeyCode.Spec.CHARACTERS_MAX,
|
||||
"i_min" to KeyCode.Spec.INTERNAL_MIN,
|
||||
"i_max" to KeyCode.Spec.INTERNAL_MAX,
|
||||
),
|
||||
color = MaterialTheme.colors.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
* 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.common
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ViewFlipper
|
||||
|
||||
/**
|
||||
* Custom ViewFlipper class used to prevent an unnecessary exception to be thrown when it is
|
||||
* detached from a window.
|
||||
*
|
||||
* Based on the solution of this SO answer: https://stackoverflow.com/a/8208874/6801193
|
||||
*/
|
||||
class FlorisViewFlipper : ViewFlipper {
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
try {
|
||||
super.onDetachedFromWindow()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
stopFlipping()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.core
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import androidx.collection.forEach
|
||||
import androidx.collection.set
|
||||
import dev.patrickgold.florisboard.debug.LogTopic
|
||||
import dev.patrickgold.florisboard.debug.flogDebug
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
|
||||
/**
|
||||
* The main logic point of processing input events and delegating them to the registered event receivers. Currently,
|
||||
* only [InputKeyEvent]s are supported, but in the future this class is thought to be the single point where input
|
||||
* events can be dispatched.
|
||||
*/
|
||||
class InputEventDispatcher private constructor(
|
||||
channelCapacity: Int,
|
||||
private val mainDispatcher: CoroutineDispatcher,
|
||||
private val defaultDispatcher: CoroutineDispatcher,
|
||||
private val repeatableKeyCodes: IntArray
|
||||
) : InputKeyEventSender {
|
||||
private val channel: Channel<InputKeyEvent> = Channel(channelCapacity)
|
||||
private val mainScope: CoroutineScope = CoroutineScope(mainDispatcher + SupervisorJob())
|
||||
private val defaultScope: CoroutineScope = CoroutineScope(defaultDispatcher + SupervisorJob())
|
||||
private val pressedKeys: SparseArrayCompat<PressedKeyInfo> = SparseArrayCompat()
|
||||
var lastKeyEventDown: InputKeyEvent? = null
|
||||
private set
|
||||
var lastKeyEventUp: InputKeyEvent? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* The input key event register. If null, the dispatcher will still process input, but won't dispatch them to an
|
||||
* event receiver.
|
||||
*/
|
||||
var keyEventReceiver: InputKeyEventReceiver? = null
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* The default input event channel capacity to be used in [new].
|
||||
*/
|
||||
private const val DEFAULT_CHANNEL_CAPACITY: Int = 64
|
||||
|
||||
/**
|
||||
* Creates a new [InputEventDispatcher] instance from given arguments and returns it.
|
||||
*
|
||||
* @param channelCapacity The capacity of this input channel, defaults to [DEFAULT_CHANNEL_CAPACITY].
|
||||
* @param mainDispatcher The main dispatcher used to switch the context to call the receiver callbacks.
|
||||
* Defaults to [Dispatchers.Main].
|
||||
* @param defaultDispatcher The default dispatcher used to switch the context to call the receiver callbacks.
|
||||
* Defaults to [Dispatchers.Default].
|
||||
* @param repeatableKeyCodes An int array of all key codes which are repeatable while being pressed down.
|
||||
*
|
||||
* @return A new [InputEventDispatcher] instance initialized with given arguments.
|
||||
*/
|
||||
fun new(
|
||||
channelCapacity: Int = DEFAULT_CHANNEL_CAPACITY,
|
||||
mainDispatcher: CoroutineDispatcher = Dispatchers.Main.immediate,
|
||||
defaultDispatcher: CoroutineDispatcher = Dispatchers.Default,
|
||||
repeatableKeyCodes: IntArray = intArrayOf()
|
||||
): InputEventDispatcher = InputEventDispatcher(
|
||||
channelCapacity, mainDispatcher, defaultDispatcher, repeatableKeyCodes.clone()
|
||||
)
|
||||
|
||||
private fun <T> SparseArrayCompat<T>.removeAndReturn(key: Int): T? {
|
||||
val elem = get(key)
|
||||
return if (elem == null) {
|
||||
null
|
||||
} else {
|
||||
remove(key)
|
||||
elem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
defaultScope.launch {
|
||||
for (ev in channel) {
|
||||
if (!isActive) break
|
||||
val startTime = System.nanoTime()
|
||||
flogDebug(LogTopic.KEY_EVENTS) { ev.toString() }
|
||||
when (ev.action) {
|
||||
InputKeyEvent.Action.DOWN -> {
|
||||
if (pressedKeys.indexOfKey(ev.data.code) >= 0) continue
|
||||
pressedKeys[ev.data.code] = PressedKeyInfo(
|
||||
eventTimeDown = ev.eventTime,
|
||||
repeatKeyPressJob = if (!repeatableKeyCodes.contains(ev.data.code)) { null } else {
|
||||
defaultScope.launch {
|
||||
delay(600)
|
||||
while (isActive) {
|
||||
channel.send(InputKeyEvent.repeat(ev.data))
|
||||
delay(50)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
withContext(mainDispatcher) {
|
||||
keyEventReceiver?.onInputKeyDown(ev)
|
||||
}
|
||||
if (ev.data.code != KeyCode.INTERNAL_BATCH_EDIT) {
|
||||
lastKeyEventDown = ev
|
||||
}
|
||||
}
|
||||
InputKeyEvent.Action.DOWN_UP -> {
|
||||
pressedKeys.removeAndReturn(ev.data.code)?.repeatKeyPressJob?.cancel()
|
||||
withContext(mainDispatcher) {
|
||||
keyEventReceiver?.onInputKeyDown(ev)
|
||||
keyEventReceiver?.onInputKeyUp(ev)
|
||||
}
|
||||
if (ev.data.code != KeyCode.INTERNAL_BATCH_EDIT) {
|
||||
lastKeyEventDown = ev
|
||||
lastKeyEventUp = ev
|
||||
}
|
||||
}
|
||||
InputKeyEvent.Action.UP -> {
|
||||
pressedKeys.removeAndReturn(ev.data.code)?.repeatKeyPressJob?.cancel()
|
||||
withContext(mainDispatcher) {
|
||||
keyEventReceiver?.onInputKeyUp(ev)
|
||||
}
|
||||
if (ev.data.code != KeyCode.INTERNAL_BATCH_EDIT) {
|
||||
lastKeyEventUp = ev
|
||||
}
|
||||
}
|
||||
InputKeyEvent.Action.REPEAT -> {
|
||||
if (pressedKeys.indexOfKey(ev.data.code) >= 0) {
|
||||
withContext(mainDispatcher) {
|
||||
keyEventReceiver?.onInputKeyRepeat(ev)
|
||||
}
|
||||
}
|
||||
}
|
||||
InputKeyEvent.Action.CANCEL -> {
|
||||
pressedKeys.removeAndReturn(ev.data.code)?.repeatKeyPressJob?.cancel()
|
||||
withContext(mainDispatcher) {
|
||||
keyEventReceiver?.onInputKeyCancel(ev)
|
||||
}
|
||||
}
|
||||
}
|
||||
flogDebug(LogTopic.KEY_EVENTS) { "Time elapsed: ${(System.nanoTime() - startTime) / 1_000_000}" }
|
||||
}
|
||||
pressedKeys.forEach { _, value -> value.repeatKeyPressJob?.cancel() }
|
||||
pressedKeys.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun send(ev: InputKeyEvent) {
|
||||
channel.trySend(ev)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there's currently a key down with given [code].
|
||||
*
|
||||
* @param code The key code to check for.
|
||||
*
|
||||
* @return True if the given [code] is currently down, false otherwise.
|
||||
*/
|
||||
fun isPressed(code: Int): Boolean {
|
||||
return pressedKeys.indexOfKey(code) >= 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this dispatcher and cancels the local coroutine scope.
|
||||
*/
|
||||
fun close() {
|
||||
keyEventReceiver = null
|
||||
mainScope.cancel()
|
||||
defaultScope.cancel()
|
||||
}
|
||||
|
||||
data class PressedKeyInfo(
|
||||
val eventTimeDown: Long,
|
||||
val repeatKeyPressJob: Job?
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class representing a single input key event.
|
||||
*
|
||||
* @property eventTime The exact event time when this event occurred, measured in milliseconds since a static point in
|
||||
* the past. The exact point is irrelevant, but while this input dispatcher is active, the point must not change in
|
||||
* order for difference time calculation to succeed.
|
||||
* @property action The action of this event.
|
||||
* @property data The data of this event.
|
||||
* @property count The count how often this event occurred. Is only respected by other methods if the [action] of this
|
||||
* event is [Action.DOWN_UP] or [Action.REPEAT], else always 1 is assumed.
|
||||
*/
|
||||
data class InputKeyEvent(
|
||||
val eventTime: Long,
|
||||
val action: Action,
|
||||
val data: KeyData,
|
||||
val count: Int
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
* Creates a new input key event with given [keyData] and sets the action to [Action.DOWN].
|
||||
*
|
||||
* @param keyData The key data of the input key event event to create.
|
||||
*
|
||||
* @return The created input key event.
|
||||
*/
|
||||
fun down(keyData: KeyData): InputKeyEvent {
|
||||
return InputKeyEvent(
|
||||
eventTime = SystemClock.uptimeMillis(),
|
||||
action = Action.DOWN,
|
||||
data = keyData,
|
||||
count = 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input key event with given [keyData] and sets the action to [Action.DOWN_UP].
|
||||
*
|
||||
* @param keyData The key data of the input key event event to create.
|
||||
* @param count How often this event occurred. Must be grater or equal to 1, defaults to 1.
|
||||
*
|
||||
* @return The created input key event.
|
||||
*/
|
||||
fun downUp(keyData: KeyData, count: Int = 1): InputKeyEvent {
|
||||
return InputKeyEvent(
|
||||
eventTime = SystemClock.uptimeMillis(),
|
||||
action = Action.DOWN_UP,
|
||||
data = keyData,
|
||||
count = count
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input key event with given [keyData] and sets the action to [Action.UP].
|
||||
*
|
||||
* @param keyData The key data of the input key event event to create.
|
||||
*
|
||||
* @return The created input key event.
|
||||
*/
|
||||
fun up(keyData: KeyData): InputKeyEvent {
|
||||
return InputKeyEvent(
|
||||
eventTime = SystemClock.uptimeMillis(),
|
||||
action = Action.UP,
|
||||
data = keyData,
|
||||
count = 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input key event with given [keyData] and sets the action to [Action.REPEAT].
|
||||
*
|
||||
* @param keyData The key data of the input key event event to create.
|
||||
* @param count How often this event occurred. Must be grater or equal to 1, defaults to 1.
|
||||
*
|
||||
* @return The created input key event.
|
||||
*/
|
||||
fun repeat(keyData: KeyData, count: Int = 1): InputKeyEvent {
|
||||
return InputKeyEvent(
|
||||
eventTime = SystemClock.uptimeMillis(),
|
||||
action = Action.REPEAT,
|
||||
data = keyData,
|
||||
count = count
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input key event with given [keyData] and sets the action to [Action.CANCEL].
|
||||
*
|
||||
* @param keyData The key data of the input key event event to create.
|
||||
*
|
||||
* @return The created input key event.
|
||||
*/
|
||||
fun cancel(keyData: KeyData): InputKeyEvent {
|
||||
return InputKeyEvent(
|
||||
eventTime = SystemClock.uptimeMillis(),
|
||||
action = Action.CANCEL,
|
||||
data = keyData,
|
||||
count = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the [other] input key event is a consecutive event while respecting [maxEventTimeDiff].
|
||||
*
|
||||
* @param other The other input key event to compare with this one.
|
||||
* @param maxEventTimeDiff The maximum event time diff between this event and [other], in milliseconds.
|
||||
*
|
||||
* @return True if this event is a consecutive event of [other], false otherwise.
|
||||
*/
|
||||
fun isConsecutiveEventOf(other: InputKeyEvent?, maxEventTimeDiff: Long): Boolean {
|
||||
return other != null && data.code == other.data.code && eventTime - other.eventTime <= maxEventTimeDiff
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this input key event.
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return "FlorisKeyEvent { eventTime=${eventTime}ms, action=$action, data=$data, count=$count }"
|
||||
}
|
||||
|
||||
/**
|
||||
* The action of an input key event.
|
||||
*/
|
||||
enum class Action {
|
||||
DOWN,
|
||||
DOWN_UP,
|
||||
UP,
|
||||
REPEAT,
|
||||
CANCEL,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface which represents an input key event sender.
|
||||
*/
|
||||
interface InputKeyEventSender {
|
||||
/**
|
||||
* Sends given input key event [ev] to the underlying input channel, awaiting to be processed.
|
||||
*
|
||||
* @param ev The input key event to send.
|
||||
*/
|
||||
fun send(ev: InputKeyEvent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface which represents an input key event receiver.
|
||||
*/
|
||||
interface InputKeyEventReceiver {
|
||||
/**
|
||||
* Event method which gets called when a key went down.
|
||||
*
|
||||
* @param ev The associated input key event.
|
||||
*/
|
||||
fun onInputKeyDown(ev: InputKeyEvent)
|
||||
|
||||
/**
|
||||
* Event method which gets called when a key went up.
|
||||
*
|
||||
* @param ev The associated input key event.
|
||||
*/
|
||||
fun onInputKeyUp(ev: InputKeyEvent)
|
||||
|
||||
/**
|
||||
* Event method which gets called when a key is called repeatedly while being pressed down.
|
||||
*
|
||||
* @param ev The associated input key event.
|
||||
*/
|
||||
fun onInputKeyRepeat(ev: InputKeyEvent)
|
||||
|
||||
/**
|
||||
* Event method which gets called when a key press is cancelled.
|
||||
*
|
||||
* @param ev The associated input key event.
|
||||
*/
|
||||
fun onInputKeyCancel(ev: InputKeyEvent)
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package dev.patrickgold.florisboard.ime.keyboard
|
||||
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
|
||||
/**
|
||||
* Class which holds the same information as an [EditorInfo.imeOptions] int but more accessible and
|
||||
* readable.
|
||||
*/
|
||||
@JvmInline
|
||||
value class ImeOptions(val state: KeyboardState) {
|
||||
companion object {
|
||||
const val M_IME_OPTIONS: ULong = 0x0F_FFu
|
||||
const val O_IME_OPTIONS: Int = 32
|
||||
|
||||
const val M_ENTER_ACTION: ULong = 0x0Fu
|
||||
const val O_ENTER_ACTION: Int = 32
|
||||
|
||||
const val F_FORCE_ASCII: ULong = 0x00_00_00_10_00_00_00_00u
|
||||
const val F_NAVIGATE_NEXT: ULong = 0x00_00_00_20_00_00_00_00u
|
||||
const val F_NAVIGATE_PREVIOUS: ULong = 0x00_00_00_40_00_00_00_00u
|
||||
const val F_NO_ACCESSORY_ACTION: ULong = 0x00_00_00_80_00_00_00_00u
|
||||
const val F_NO_ENTER_ACTION: ULong = 0x00_00_01_00_00_00_00_00u
|
||||
const val F_NO_EXTRACT_UI: ULong = 0x00_00_02_00_00_00_00_00u
|
||||
const val F_NO_FULLSCREEN: ULong = 0x00_00_04_00_00_00_00_00u
|
||||
const val F_NO_PERSONALIZED_LEARNING: ULong = 0x00_00_08_00_00_00_00_00u
|
||||
}
|
||||
|
||||
var enterAction: EnterAction
|
||||
get() = EnterAction.fromInt(state.getRegion(M_ENTER_ACTION, O_ENTER_ACTION))
|
||||
private set(v) = state.setRegion(M_ENTER_ACTION, O_ENTER_ACTION, v.toInt())
|
||||
|
||||
var flagForceAscii: Boolean
|
||||
get() = state.getFlag(F_FORCE_ASCII)
|
||||
private set(v) = state.setFlag(F_FORCE_ASCII, v)
|
||||
var flagNavigateNext: Boolean
|
||||
get() = state.getFlag(F_NAVIGATE_NEXT)
|
||||
private set(v) = state.setFlag(F_NAVIGATE_NEXT, v)
|
||||
var flagNavigatePrevious: Boolean
|
||||
get() = state.getFlag(F_NAVIGATE_PREVIOUS)
|
||||
private set(v) = state.setFlag(F_NAVIGATE_PREVIOUS, v)
|
||||
var flagNoAccessoryAction: Boolean
|
||||
get() = state.getFlag(F_NO_ACCESSORY_ACTION)
|
||||
private set(v) = state.setFlag(F_NO_ACCESSORY_ACTION, v)
|
||||
var flagNoEnterAction: Boolean
|
||||
get() = state.getFlag(F_NO_ENTER_ACTION)
|
||||
private set(v) = state.setFlag(F_NO_ENTER_ACTION, v)
|
||||
var flagNoExtractUi: Boolean
|
||||
get() = state.getFlag(F_NO_EXTRACT_UI)
|
||||
private set(v) = state.setFlag(F_NO_EXTRACT_UI, v)
|
||||
var flagNoFullscreen: Boolean
|
||||
get() = state.getFlag(F_NO_FULLSCREEN)
|
||||
private set(v) = state.setFlag(F_NO_FULLSCREEN, v)
|
||||
var flagNoPersonalizedLearning: Boolean
|
||||
get() = state.getFlag(F_NO_PERSONALIZED_LEARNING)
|
||||
private set(v) = state.setFlag(F_NO_PERSONALIZED_LEARNING, v)
|
||||
|
||||
fun update(editorInfo: EditorInfo) {
|
||||
val imeOptionsRaw = editorInfo.imeOptions
|
||||
state.setRegion(M_IME_OPTIONS, O_IME_OPTIONS, 0) // reset imeOptions region
|
||||
enterAction = EnterAction.fromInt(imeOptionsRaw and EditorInfo.IME_MASK_ACTION)
|
||||
flagForceAscii = imeOptionsRaw and EditorInfo.IME_FLAG_FORCE_ASCII != 0
|
||||
flagNavigateNext = imeOptionsRaw and EditorInfo.IME_FLAG_NAVIGATE_NEXT != 0
|
||||
flagNavigatePrevious = imeOptionsRaw and EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS != 0
|
||||
flagNoAccessoryAction = imeOptionsRaw and EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION != 0
|
||||
flagNoEnterAction = imeOptionsRaw and EditorInfo.IME_FLAG_NO_ENTER_ACTION != 0
|
||||
flagNoExtractUi = imeOptionsRaw and EditorInfo.IME_FLAG_NO_EXTRACT_UI != 0
|
||||
flagNoFullscreen = imeOptionsRaw and EditorInfo.IME_FLAG_NO_FULLSCREEN != 0
|
||||
if (AndroidVersion.ATLEAST_API26_O) {
|
||||
flagNoPersonalizedLearning = imeOptionsRaw and EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING != 0
|
||||
}
|
||||
}
|
||||
|
||||
enum class EnterAction(val value: Int) {
|
||||
UNSPECIFIED(EditorInfo.IME_ACTION_UNSPECIFIED),
|
||||
DONE(EditorInfo.IME_ACTION_DONE),
|
||||
GO(EditorInfo.IME_ACTION_GO),
|
||||
NEXT(EditorInfo.IME_ACTION_NEXT),
|
||||
NONE(EditorInfo.IME_ACTION_NONE),
|
||||
PREVIOUS(EditorInfo.IME_ACTION_PREVIOUS),
|
||||
SEARCH(EditorInfo.IME_ACTION_SEARCH),
|
||||
SEND(EditorInfo.IME_ACTION_SEND);
|
||||
|
||||
companion object {
|
||||
fun fromInt(int: Int) = values().firstOrNull { it.value == int } ?: NONE
|
||||
}
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package dev.patrickgold.florisboard.ime.keyboard
|
||||
|
||||
import android.text.InputType
|
||||
import android.view.inputmethod.EditorInfo
|
||||
|
||||
/**
|
||||
* Class which holds the same information as an [EditorInfo.inputType] int but more accessible and
|
||||
* readable.
|
||||
*/
|
||||
@JvmInline
|
||||
value class InputAttributes(val state: KeyboardState) {
|
||||
companion object {
|
||||
const val M_INPUT_ATTRIBUTES: ULong = 0x0F_FF_FFu
|
||||
const val O_INPUT_ATTRIBUTES: Int = 44
|
||||
|
||||
const val M_TYPE: ULong = 0x07u
|
||||
const val O_TYPE: Int = 44
|
||||
const val M_VARIATION: ULong = 0x1Fu
|
||||
const val O_VARIATION: Int = 47
|
||||
const val M_CAPS_MODE: ULong = 0x03u
|
||||
const val O_CAPS_MODE: Int = 52
|
||||
|
||||
const val F_NUMBER_DECIMAL: ULong = 0x00_40_00_00_00_00_00_00u
|
||||
const val F_NUMBER_SIGNED: ULong = 0x00_80_00_00_00_00_00_00u
|
||||
const val F_TEXT_AUTO_COMPLETE: ULong = 0x01_00_00_00_00_00_00_00u
|
||||
const val F_TEXT_AUTO_CORRECT: ULong = 0x02_00_00_00_00_00_00_00u
|
||||
const val F_TEXT_IME_MULTILINE: ULong = 0x04_00_00_00_00_00_00_00u
|
||||
const val F_TEXT_MULTILINE: ULong = 0x08_00_00_00_00_00_00_00u
|
||||
const val F_TEXT_NO_SUGGESTIONS: ULong = 0x10_00_00_00_00_00_00_00u
|
||||
}
|
||||
|
||||
var type: Type
|
||||
get() = Type.fromInt(state.getRegion(M_TYPE, O_TYPE))
|
||||
private set(v) = state.setRegion(M_TYPE, O_TYPE, v.toInt())
|
||||
|
||||
var variation: Variation
|
||||
get() = Variation.fromInt(state.getRegion(M_VARIATION, O_VARIATION))
|
||||
private set(v) = state.setRegion(M_VARIATION, O_VARIATION, v.toInt())
|
||||
|
||||
var capsMode: CapsMode
|
||||
get() = CapsMode.fromInt(state.getRegion(M_CAPS_MODE, O_CAPS_MODE))
|
||||
private set(v) = state.setRegion(M_CAPS_MODE, O_CAPS_MODE, v.toInt())
|
||||
|
||||
var flagNumberDecimal: Boolean
|
||||
get() = state.getFlag(F_NUMBER_DECIMAL)
|
||||
private set(v) = state.setFlag(F_NUMBER_DECIMAL, v)
|
||||
var flagNumberSigned: Boolean
|
||||
get() = state.getFlag(F_NUMBER_SIGNED)
|
||||
private set(v) = state.setFlag(F_NUMBER_SIGNED, v)
|
||||
var flagTextAutoComplete: Boolean
|
||||
get() = state.getFlag(F_TEXT_AUTO_COMPLETE)
|
||||
private set(v) = state.setFlag(F_TEXT_AUTO_COMPLETE, v)
|
||||
var flagTextAutoCorrect: Boolean
|
||||
get() = state.getFlag(F_TEXT_AUTO_CORRECT)
|
||||
private set(v) = state.setFlag(F_TEXT_AUTO_CORRECT, v)
|
||||
var flagTextImeMultiLine: Boolean
|
||||
get() = state.getFlag(F_TEXT_IME_MULTILINE)
|
||||
private set(v) = state.setFlag(F_TEXT_IME_MULTILINE, v)
|
||||
var flagTextMultiLine: Boolean
|
||||
get() = state.getFlag(F_TEXT_MULTILINE)
|
||||
private set(v) = state.setFlag(F_TEXT_MULTILINE, v)
|
||||
var flagTextNoSuggestions: Boolean
|
||||
get() = state.getFlag(F_TEXT_NO_SUGGESTIONS)
|
||||
private set(v) = state.setFlag(F_TEXT_NO_SUGGESTIONS, v)
|
||||
|
||||
fun update(editorInfo: EditorInfo) {
|
||||
val inputAttrsRaw = editorInfo.inputType
|
||||
state.setRegion(M_INPUT_ATTRIBUTES, O_INPUT_ATTRIBUTES, 0) // reset inputAttributes region
|
||||
when (inputAttrsRaw and InputType.TYPE_MASK_CLASS) {
|
||||
InputType.TYPE_NULL -> {
|
||||
type = Type.NULL
|
||||
variation = Variation.NORMAL
|
||||
capsMode = CapsMode.NONE
|
||||
}
|
||||
InputType.TYPE_CLASS_DATETIME -> {
|
||||
type = Type.DATETIME
|
||||
variation = when (inputAttrsRaw and InputType.TYPE_MASK_VARIATION) {
|
||||
InputType.TYPE_DATETIME_VARIATION_DATE -> Variation.DATE
|
||||
InputType.TYPE_DATETIME_VARIATION_NORMAL -> Variation.NORMAL
|
||||
InputType.TYPE_DATETIME_VARIATION_TIME -> Variation.TIME
|
||||
else -> Variation.NORMAL
|
||||
}
|
||||
capsMode = CapsMode.NONE
|
||||
}
|
||||
InputType.TYPE_CLASS_NUMBER -> {
|
||||
type = Type.NUMBER
|
||||
variation = when (inputAttrsRaw and InputType.TYPE_MASK_VARIATION) {
|
||||
InputType.TYPE_NUMBER_VARIATION_NORMAL -> Variation.NORMAL
|
||||
InputType.TYPE_NUMBER_VARIATION_PASSWORD -> Variation.PASSWORD
|
||||
else -> Variation.NORMAL
|
||||
}
|
||||
capsMode = CapsMode.NONE
|
||||
flagNumberDecimal = inputAttrsRaw and InputType.TYPE_NUMBER_FLAG_DECIMAL != 0
|
||||
flagNumberSigned = inputAttrsRaw and InputType.TYPE_NUMBER_FLAG_SIGNED != 0
|
||||
}
|
||||
InputType.TYPE_CLASS_PHONE -> {
|
||||
type = Type.PHONE
|
||||
variation = Variation.NORMAL
|
||||
capsMode = CapsMode.NONE
|
||||
}
|
||||
InputType.TYPE_CLASS_TEXT -> {
|
||||
type = Type.TEXT
|
||||
variation = when (inputAttrsRaw and InputType.TYPE_MASK_VARIATION) {
|
||||
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS -> Variation.EMAIL_ADDRESS
|
||||
InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT -> Variation.EMAIL_SUBJECT
|
||||
InputType.TYPE_TEXT_VARIATION_FILTER -> Variation.FILTER
|
||||
InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE -> Variation.LONG_MESSAGE
|
||||
InputType.TYPE_TEXT_VARIATION_NORMAL -> Variation.NORMAL
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD -> Variation.PASSWORD
|
||||
InputType.TYPE_TEXT_VARIATION_PERSON_NAME -> Variation.PERSON_NAME
|
||||
InputType.TYPE_TEXT_VARIATION_PHONETIC -> Variation.PHONETIC
|
||||
InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS -> Variation.POSTAL_ADDRESS
|
||||
InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE -> Variation.SHORT_MESSAGE
|
||||
InputType.TYPE_TEXT_VARIATION_URI -> Variation.URI
|
||||
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD -> Variation.VISIBLE_PASSWORD
|
||||
InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT -> Variation.WEB_EDIT_TEXT
|
||||
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS -> Variation.WEB_EMAIL_ADDRESS
|
||||
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD -> Variation.WEB_PASSWORD
|
||||
else -> Variation.NORMAL
|
||||
}
|
||||
capsMode = CapsMode.fromFlags(inputAttrsRaw)
|
||||
flagTextAutoComplete = inputAttrsRaw and InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE != 0
|
||||
flagTextAutoCorrect = inputAttrsRaw and InputType.TYPE_TEXT_FLAG_AUTO_CORRECT != 0
|
||||
flagTextImeMultiLine = inputAttrsRaw and InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE != 0
|
||||
flagTextMultiLine = inputAttrsRaw and InputType.TYPE_TEXT_FLAG_MULTI_LINE != 0
|
||||
flagTextNoSuggestions = inputAttrsRaw and InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS != 0
|
||||
}
|
||||
else -> {
|
||||
type = Type.TEXT
|
||||
variation = Variation.NORMAL
|
||||
capsMode = CapsMode.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Type(val value: Int) {
|
||||
NULL(EditorInfo.TYPE_NULL),
|
||||
DATETIME(EditorInfo.TYPE_CLASS_DATETIME),
|
||||
NUMBER(EditorInfo.TYPE_CLASS_NUMBER),
|
||||
PHONE(EditorInfo.TYPE_CLASS_PHONE),
|
||||
TEXT(EditorInfo.TYPE_CLASS_TEXT);
|
||||
|
||||
companion object {
|
||||
fun fromInt(int: Int) = values().firstOrNull { it.value == int } ?: NULL
|
||||
}
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
|
||||
enum class Variation(val value: Int) {
|
||||
NORMAL(0),
|
||||
DATE(1),
|
||||
EMAIL_ADDRESS(2),
|
||||
EMAIL_SUBJECT(3),
|
||||
FILTER(4),
|
||||
LONG_MESSAGE(5),
|
||||
PASSWORD(6),
|
||||
PERSON_NAME(7),
|
||||
PHONETIC(8),
|
||||
POSTAL_ADDRESS(9),
|
||||
SHORT_MESSAGE(10),
|
||||
TIME(11),
|
||||
URI(12),
|
||||
VISIBLE_PASSWORD(13),
|
||||
WEB_EDIT_TEXT(14),
|
||||
WEB_EMAIL_ADDRESS(15),
|
||||
WEB_PASSWORD(16);
|
||||
|
||||
companion object {
|
||||
fun fromInt(int: Int) = values().firstOrNull { it.value == int } ?: NORMAL
|
||||
}
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
|
||||
enum class CapsMode(val value: Int) {
|
||||
NONE(0),
|
||||
ALL(1),
|
||||
SENTENCES(2),
|
||||
WORDS(3);
|
||||
|
||||
companion object {
|
||||
fun fromFlags(flags: Int): CapsMode {
|
||||
return when {
|
||||
flags and InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS != 0 -> ALL
|
||||
flags and InputType.TYPE_TEXT_FLAG_CAP_SENTENCES != 0 -> SENTENCES
|
||||
flags and InputType.TYPE_TEXT_FLAG_CAP_WORDS != 0 -> WORDS
|
||||
else -> NONE
|
||||
}
|
||||
}
|
||||
|
||||
fun fromInt(int: Int) = values().firstOrNull { it.value == int } ?: NONE
|
||||
}
|
||||
|
||||
fun toFlags(): Int {
|
||||
return when (this) {
|
||||
ALL -> InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
|
||||
SENTENCES -> InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
||||
WORDS -> InputType.TYPE_TEXT_FLAG_CAP_WORDS
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.nlp
|
||||
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
|
||||
@Suppress("RegExpRedundantEscape")
|
||||
object TextProcessor {
|
||||
private val LATIN_BASIC_WORD_REGEX = """[_]*(([\p{L}\d\']+[_-]*[\p{L}\d\']+)|[\p{L}\d\']+)[_]*""".toRegex()
|
||||
|
||||
private fun wordRegexFor(locale: FlorisLocale): Regex {
|
||||
return when (locale) {
|
||||
else -> LATIN_BASIC_WORD_REGEX
|
||||
}
|
||||
}
|
||||
|
||||
fun detectWords(text: CharSequence, locale: FlorisLocale): Sequence<IntRange> {
|
||||
val regex = wordRegexFor(locale)
|
||||
return regex.findAll(text).map { it.range }
|
||||
}
|
||||
|
||||
fun detectWords(text: CharSequence, start: Int, end: Int, locale: FlorisLocale): Sequence<IntRange> {
|
||||
val regex = wordRegexFor(locale)
|
||||
val tStart = start.coerceAtLeast(0)
|
||||
val tEnd = end.coerceAtMost(text.length)
|
||||
return regex.findAll(text.slice(tStart..tEnd)).map { it.range }
|
||||
}
|
||||
|
||||
fun isWord(text: CharSequence, locale: FlorisLocale): Boolean {
|
||||
val regex = wordRegexFor(locale)
|
||||
return regex.matches(text)
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
* 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.text.key
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
|
||||
|
||||
/**
|
||||
* Enum for the input modes of a text keyboard.
|
||||
*/
|
||||
enum class InputMode(val value: Int) {
|
||||
/**
|
||||
* The default input mode.
|
||||
*/
|
||||
NORMAL(0),
|
||||
/**
|
||||
* Shift lock is active, but not persistent after character input. Symbol rows are shifted.
|
||||
*/
|
||||
SHIFT_LOCK(1),
|
||||
/**
|
||||
* Shift lock is active, but persistent after character input = Caps lock. Symbol rows are not shifted.
|
||||
*/
|
||||
CAPS_LOCK(2);
|
||||
|
||||
companion object {
|
||||
fun fromInt(int: Int) = values().firstOrNull { it.value == int } ?: NORMAL
|
||||
|
||||
@Composable
|
||||
fun listEntries() = listPrefEntries {
|
||||
entry(
|
||||
key = NORMAL,
|
||||
label = stringRes(R.string.enum__input_mode__normal),
|
||||
)
|
||||
entry(
|
||||
key = SHIFT_LOCK,
|
||||
label = stringRes(R.string.enum__input_mode__shift_lock),
|
||||
)
|
||||
entry(
|
||||
key = CAPS_LOCK,
|
||||
label = stringRes(R.string.enum__input_mode__caps_lock),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
@@ -22,28 +22,29 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import androidx.core.os.UserManagerCompat
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.common.NativeStr
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.toNativeStr
|
||||
import dev.patrickgold.florisboard.crashutility.CrashUtility
|
||||
import dev.patrickgold.florisboard.debug.Flog
|
||||
import dev.patrickgold.florisboard.debug.LogTopic
|
||||
import dev.patrickgold.florisboard.debug.flogError
|
||||
import dev.patrickgold.florisboard.debug.flogInfo
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.clipboard.ClipboardManager
|
||||
import dev.patrickgold.florisboard.ime.core.SubtypeManager
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorInstance
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardManager
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.FlorisEmojiCompat
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpManager
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingManager
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingService
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.GlideTypingManager
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeManager
|
||||
import dev.patrickgold.florisboard.res.AssetManager
|
||||
import dev.patrickgold.florisboard.res.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.res.io.deleteContentsRecursively
|
||||
import dev.patrickgold.florisboard.lib.NativeStr
|
||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.crashutility.CrashUtility
|
||||
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.devtools.flogInfo
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.lib.io.AssetManager
|
||||
import dev.patrickgold.florisboard.lib.io.deleteContentsRecursively
|
||||
import dev.patrickgold.florisboard.lib.toNativeStr
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import java.io.File
|
||||
|
||||
@@ -67,6 +68,7 @@ class FlorisApplication : Application() {
|
||||
val assetManager = lazy { AssetManager(this) }
|
||||
val cacheManager = lazy { CacheManager(this) }
|
||||
val clipboardManager = lazy { ClipboardManager(this) }
|
||||
val editorInstance = lazy { EditorInstance(this) }
|
||||
val extensionManager = lazy { ExtensionManager(this) }
|
||||
val glideTypingManager = lazy { GlideTypingManager(this) }
|
||||
val keyboardManager = lazy { KeyboardManager(this) }
|
||||
@@ -88,8 +90,9 @@ class FlorisApplication : Application() {
|
||||
flogOutputs = Flog.OUTPUT_CONSOLE,
|
||||
)
|
||||
CrashUtility.install(this)
|
||||
FlorisEmojiCompat.init(this)
|
||||
|
||||
if (AndroidVersion.ATLEAST_API24_N && !UserManagerCompat.isUserUnlocked(this)) {
|
||||
if (!UserManagerCompat.isUserUnlocked(this)) {
|
||||
val context = createDeviceProtectedStorageContext()
|
||||
initICU(context)
|
||||
prefs.initializeBlocking(context)
|
||||
@@ -162,6 +165,8 @@ fun Context.cacheManager() = lazy { this.florisApplication().cacheManager.value
|
||||
|
||||
fun Context.clipboardManager() = lazy { this.florisApplication().clipboardManager.value }
|
||||
|
||||
fun Context.editorInstance() = lazy { this.florisApplication().editorInstance.value }
|
||||
|
||||
fun Context.extensionManager() = lazy { this.florisApplication().extensionManager.value }
|
||||
|
||||
fun Context.glideTypingManager() = lazy { this.florisApplication().glideTypingManager.value }
|
||||
@@ -19,70 +19,68 @@ package dev.patrickgold.florisboard
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.inputmethodservice.ExtractEditText
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Size
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.ExtractedText
|
||||
import android.view.inputmethod.InlineSuggestionsRequest
|
||||
import android.view.inputmethod.InlineSuggestionsResponse
|
||||
import android.view.inputmethod.InputConnection
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.inline.InlinePresentationSpec
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.pointer.pointerInteropFilter
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.AbstractComposeView
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.WindowCompat
|
||||
import dev.patrickgold.florisboard.app.FlorisAppActivity
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.res.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.app.ui.components.SystemUiIme
|
||||
import dev.patrickgold.florisboard.app.ui.devtools.DevtoolsOverlay
|
||||
import dev.patrickgold.florisboard.common.ViewUtils
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationLandscape
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationPortrait
|
||||
import dev.patrickgold.florisboard.common.android.launchActivity
|
||||
import dev.patrickgold.florisboard.common.android.setLocale
|
||||
import dev.patrickgold.florisboard.common.android.systemServiceOrNull
|
||||
import dev.patrickgold.florisboard.common.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.debug.LogTopic
|
||||
import dev.patrickgold.florisboard.debug.flogError
|
||||
import dev.patrickgold.florisboard.debug.flogInfo
|
||||
import dev.patrickgold.florisboard.debug.flogWarning
|
||||
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.EditorInstance
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorRange
|
||||
import dev.patrickgold.florisboard.ime.editor.FlorisEditorInfo
|
||||
import dev.patrickgold.florisboard.ime.input.InputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.keyboard.InputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.ProvideKeyboardRowBaseHeight
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
import dev.patrickgold.florisboard.ime.lifecycle.LifecycleInputMethodService
|
||||
import dev.patrickgold.florisboard.ime.media.MediaInputLayout
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
@@ -91,7 +89,30 @@ import dev.patrickgold.florisboard.ime.text.TextInputLayout
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.snygg.ui.SnyggSurface
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidInternalR
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.lib.android.isOrientationLandscape
|
||||
import dev.patrickgold.florisboard.lib.android.isOrientationPortrait
|
||||
import dev.patrickgold.florisboard.lib.android.launchActivity
|
||||
import dev.patrickgold.florisboard.lib.android.setLocale
|
||||
import dev.patrickgold.florisboard.lib.android.systemServiceOrNull
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButton
|
||||
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.lib.compose.SystemUiIme
|
||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||
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 dev.patrickgold.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.shape
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.snyggBackground
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.snyggBorder
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.snyggShadow
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.solidColor
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.spSize
|
||||
import dev.patrickgold.florisboard.lib.util.ViewUtils
|
||||
import dev.patrickgold.florisboard.lib.util.debugSummarize
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@@ -107,18 +128,14 @@ private var FlorisImeServiceReference = WeakReference<FlorisImeService?>(null)
|
||||
/**
|
||||
* Core class responsible for linking together all managers and UI compose-ables to provide an IME service. Sets
|
||||
* up the window and context to be lifecycle-aware, so LiveData and Jetpack Compose can be used without issues.
|
||||
*
|
||||
* This is a new implementation for the keyboard service class and is replacing the old core class bit by bit.
|
||||
* The main objective for the new class is to hold as few state as possible and delegate tasks to context-bound
|
||||
* manager classes.
|
||||
*/
|
||||
class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHistoryChangedListener {
|
||||
class FlorisImeService : LifecycleInputMethodService() {
|
||||
companion object {
|
||||
private val InlineSuggestionUiSmallestSize = Size(0, 0)
|
||||
private val InlineSuggestionUiBiggestSize = Size(Int.MAX_VALUE, Int.MAX_VALUE)
|
||||
|
||||
fun activeEditorInstance(): EditorInstance? {
|
||||
return FlorisImeServiceReference.get()?.activeEditorInstance
|
||||
fun currentInputConnection(): InputConnection? {
|
||||
return FlorisImeServiceReference.get()?.currentInputConnection
|
||||
}
|
||||
|
||||
fun inputFeedbackController(): InputFeedbackController? {
|
||||
@@ -201,17 +218,19 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val editorInstance by editorInstance()
|
||||
private val keyboardManager by keyboardManager()
|
||||
private val nlpManager by nlpManager()
|
||||
private val subtypeManager by subtypeManager()
|
||||
private val themeManager by themeManager()
|
||||
|
||||
private val activeEditorInstance by lazy { EditorInstance(this) }
|
||||
private val activeState get() = keyboardManager.activeState
|
||||
private var inputWindowView by mutableStateOf<View?>(null)
|
||||
private var inputViewSize by mutableStateOf(IntSize.Zero)
|
||||
private val inputFeedbackController by lazy { InputFeedbackController.new(this) }
|
||||
private var isWindowShown: Boolean = false
|
||||
private var isFullscreenUiMode by mutableStateOf(false)
|
||||
private var isExtractUiShown by mutableStateOf(false)
|
||||
private var resourcesContext by mutableStateOf(this as Context)
|
||||
|
||||
init {
|
||||
@@ -221,7 +240,6 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
FlorisImeServiceReference = WeakReference(this)
|
||||
activeEditorInstance.wordHistoryChangedListener = this
|
||||
subtypeManager.activeSubtype.observe(this) { subtype ->
|
||||
val config = Configuration(resources.configuration)
|
||||
config.setLocale(subtype.primaryLocale)
|
||||
@@ -230,7 +248,7 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
}
|
||||
|
||||
override fun onCreateInputView(): View {
|
||||
super.onCreateInputView()
|
||||
super.installViewTreeOwners()
|
||||
val composeView = ComposeInputView()
|
||||
inputWindowView = composeView
|
||||
return composeView
|
||||
@@ -241,32 +259,47 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreateExtractTextView(): View {
|
||||
super.installViewTreeOwners()
|
||||
// Consider adding a fallback to the default extract edit layout if user reports come
|
||||
// that this causes a crash, especially if the device manufacturer of the user device
|
||||
// is a known one to break AOSP standards...
|
||||
val defaultExtractView = super.onCreateExtractTextView()
|
||||
if (defaultExtractView == null || defaultExtractView !is ViewGroup) {
|
||||
return ComposeExtractedLandscapeInputView(null)
|
||||
}
|
||||
val extractEditText = defaultExtractView.findViewById<ExtractEditText>(android.R.id.inputExtractEditText)
|
||||
(extractEditText?.parent as? ViewGroup)?.removeView(extractEditText)
|
||||
defaultExtractView.apply {
|
||||
removeAllViews()
|
||||
addView(ComposeExtractedLandscapeInputView(extractEditText))
|
||||
}
|
||||
return defaultExtractView
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
FlorisImeServiceReference = WeakReference(null)
|
||||
activeEditorInstance.wordHistoryChangedListener = null
|
||||
inputWindowView = null
|
||||
}
|
||||
|
||||
override fun onBindInput() {
|
||||
super.onBindInput()
|
||||
activeEditorInstance.bindInput()
|
||||
}
|
||||
|
||||
override fun onStartInput(attribute: EditorInfo?, restarting: Boolean) {
|
||||
super.onStartInput(attribute, restarting)
|
||||
if (attribute == null) return
|
||||
activeEditorInstance.startInput(attribute)
|
||||
override fun onStartInput(info: EditorInfo?, restarting: Boolean) {
|
||||
flogInfo { "restarting=$restarting info=${info?.debugSummarize()}" }
|
||||
super.onStartInput(info, restarting)
|
||||
if (info == null) return
|
||||
val editorInfo = FlorisEditorInfo.wrap(info)
|
||||
editorInstance.handleStartInput(editorInfo)
|
||||
}
|
||||
|
||||
override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
|
||||
flogInfo { "restarting=$restarting info=${info?.debugSummarize()}" }
|
||||
super.onStartInputView(info, restarting)
|
||||
if (info == null) return
|
||||
val editorInfo = FlorisEditorInfo.wrap(info)
|
||||
activeState.batchEdit {
|
||||
activeState.update(info)
|
||||
activeState.imeUiMode = ImeUiMode.TEXT
|
||||
activeState.isSelectionMode = (info.initialSelEnd - info.initialSelStart) != 0
|
||||
activeEditorInstance.startInputView(info)
|
||||
activeState.isSelectionMode = editorInfo.initialSelection.isSelectionMode
|
||||
editorInstance.handleStartInputView(editorInfo)
|
||||
keyboardManager.updateCapsState()
|
||||
}
|
||||
}
|
||||
@@ -277,51 +310,34 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
newSelStart: Int,
|
||||
newSelEnd: Int,
|
||||
candidatesStart: Int,
|
||||
candidatesEnd: Int
|
||||
candidatesEnd: Int,
|
||||
) {
|
||||
flogInfo { "old={start=$oldSelStart,end=$oldSelEnd} new={start=$newSelStart,end=$newSelEnd} composing={start=$candidatesStart,end=$candidatesEnd}" }
|
||||
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd)
|
||||
activeState.batchEdit {
|
||||
activeState.isSelectionMode = (newSelEnd - newSelStart) != 0
|
||||
activeEditorInstance.updateSelection(
|
||||
oldSelStart, oldSelEnd,
|
||||
newSelStart, newSelEnd,
|
||||
candidatesStart, candidatesEnd,
|
||||
editorInstance.handleSelectionUpdate(
|
||||
oldSelection = EditorRange.normalized(oldSelStart, oldSelEnd),
|
||||
newSelection = EditorRange.normalized(newSelStart, newSelEnd),
|
||||
composing = EditorRange.normalized(candidatesStart, candidatesEnd),
|
||||
)
|
||||
keyboardManager.updateCapsState()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinishInputView(finishingInput: Boolean) {
|
||||
flogInfo { "finishing=$finishingInput" }
|
||||
super.onFinishInputView(finishingInput)
|
||||
// TODO: evaluate which parts to reset. Resetting everything is too much,
|
||||
// resetting nothing could be problematic too.
|
||||
//activeState.reset()
|
||||
activeEditorInstance.finishInputView()
|
||||
editorInstance.handleFinishInputView()
|
||||
}
|
||||
|
||||
override fun onFinishInput() {
|
||||
flogInfo { "(no args)" }
|
||||
super.onFinishInput()
|
||||
activeEditorInstance.finishInput()
|
||||
editorInstance.handleFinishInput()
|
||||
nlpManager.clearInlineSuggestions()
|
||||
}
|
||||
|
||||
override fun onUnbindInput() {
|
||||
super.onUnbindInput()
|
||||
activeEditorInstance.unbindInput()
|
||||
}
|
||||
|
||||
override fun onWordHistoryChanged(
|
||||
currentWord: EditorInstance.Region?,
|
||||
wordsBeforeCurrent: List<EditorInstance.Region>,
|
||||
wordsAfterCurrent: List<EditorInstance.Region>,
|
||||
) {
|
||||
if (currentWord == null || !currentWord.isValid || !activeState.isComposingEnabled) {
|
||||
nlpManager.clearSuggestions()
|
||||
return
|
||||
}
|
||||
nlpManager.suggest(currentWord.text, listOf())
|
||||
}
|
||||
|
||||
override fun onWindowShown() {
|
||||
super.onWindowShown()
|
||||
if (isWindowShown) {
|
||||
@@ -345,14 +361,34 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
isWindowShown = false
|
||||
}
|
||||
|
||||
override fun onEvaluateFullscreenMode(): Boolean {
|
||||
return when (prefs.keyboard.landscapeInputUiMode.get()) {
|
||||
LandscapeInputUiMode.DYNAMICALLY_SHOW -> super.onEvaluateFullscreenMode()
|
||||
LandscapeInputUiMode.NEVER_SHOW -> false
|
||||
LandscapeInputUiMode.ALWAYS_SHOW -> true
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateFullscreenMode() {
|
||||
super.updateFullscreenMode()
|
||||
isFullscreenUiMode = isFullscreenMode
|
||||
updateSoftInputWindowLayoutParameters()
|
||||
}
|
||||
|
||||
override fun onUpdateExtractedText(token: Int, text: ExtractedText?) {
|
||||
super.onUpdateExtractedText(token, text)
|
||||
activeEditorInstance.updateText(token, text)
|
||||
override fun onUpdateExtractingVisibility(info: EditorInfo?) {
|
||||
if (info != null) {
|
||||
editorInstance.handleStartInputView(FlorisEditorInfo.wrap(info))
|
||||
}
|
||||
when (prefs.keyboard.landscapeInputUiMode.get()) {
|
||||
LandscapeInputUiMode.DYNAMICALLY_SHOW -> super.onUpdateExtractingVisibility(info)
|
||||
LandscapeInputUiMode.NEVER_SHOW -> isExtractViewShown = false
|
||||
LandscapeInputUiMode.ALWAYS_SHOW -> isExtractViewShown = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun setExtractViewShown(shown: Boolean) {
|
||||
super.setExtractViewShown(shown)
|
||||
isExtractUiShown = shown
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@@ -424,7 +460,7 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
val w = window?.window ?: return
|
||||
WindowCompat.setDecorFitsSystemWindows(w, true)
|
||||
ViewUtils.updateLayoutHeightOf(w, WindowManager.LayoutParams.MATCH_PARENT)
|
||||
val layoutHeight = if (isFullscreenMode) {
|
||||
val layoutHeight = if (isFullscreenUiMode) {
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
} else {
|
||||
WindowManager.LayoutParams.MATCH_PARENT
|
||||
@@ -436,15 +472,39 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
ViewUtils.updateLayoutHeightOf(inputWindowView, layoutHeight)
|
||||
}
|
||||
|
||||
override fun getTextForImeAction(imeOptions: Int): String? {
|
||||
return try {
|
||||
when (imeOptions and EditorInfo.IME_MASK_ACTION) {
|
||||
EditorInfo.IME_ACTION_NONE -> null
|
||||
EditorInfo.IME_ACTION_GO -> resourcesContext.getString(AndroidInternalR.string.ime_action_go)
|
||||
EditorInfo.IME_ACTION_SEARCH -> resourcesContext.getString(AndroidInternalR.string.ime_action_search)
|
||||
EditorInfo.IME_ACTION_SEND -> resourcesContext.getString(AndroidInternalR.string.ime_action_send)
|
||||
EditorInfo.IME_ACTION_NEXT -> resourcesContext.getString(AndroidInternalR.string.ime_action_next)
|
||||
EditorInfo.IME_ACTION_DONE -> resourcesContext.getString(AndroidInternalR.string.ime_action_done)
|
||||
EditorInfo.IME_ACTION_PREVIOUS -> resourcesContext.getString(AndroidInternalR.string.ime_action_previous)
|
||||
else -> resourcesContext.getString(AndroidInternalR.string.ime_action_default)
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
super.getTextForImeAction(imeOptions)?.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ImeUiWrapper() {
|
||||
ProvideLocalizedResources(resourcesContext) {
|
||||
ProvideKeyboardRowBaseHeight {
|
||||
CompositionLocalProvider(LocalInputFeedbackController provides inputFeedbackController) {
|
||||
FlorisImeTheme {
|
||||
// Outer box is necessary as an "outer window"
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
DevtoolsUi()
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
if (!(isFullscreenUiMode && isExtractUiShown)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
) {
|
||||
DevtoolsUi()
|
||||
}
|
||||
}
|
||||
ImeUi()
|
||||
}
|
||||
SystemUiIme()
|
||||
@@ -456,11 +516,11 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
private fun BoxScope.ImeUi() {
|
||||
private fun ImeUi() {
|
||||
val activeState by keyboardManager.observeActiveState()
|
||||
val keyboardStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.Keyboard,
|
||||
mode = activeState.inputMode.value,
|
||||
mode = activeState.inputShiftState.value,
|
||||
)
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
SideEffect {
|
||||
@@ -471,7 +531,6 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.align(Alignment.BottomStart)
|
||||
.onGloballyPositioned { coords -> inputViewSize = coords.size }
|
||||
// Do not remove below line or touch input may get stuck
|
||||
.pointerInteropFilter { false },
|
||||
@@ -525,23 +584,13 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.DevtoolsUi() = with(LocalDensity.current) {
|
||||
private fun DevtoolsUi() {
|
||||
val devtoolsEnabled by prefs.devtools.enabled.observeAsState()
|
||||
if (devtoolsEnabled) {
|
||||
val maxHeight = inputWindowView?.measuredHeight?.let { windowHeight ->
|
||||
windowHeight - inputViewSize.height - FlorisImeSizing.Static.smartbarHeightPx
|
||||
} ?: inputViewSize.height
|
||||
DevtoolsOverlay(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.heightIn(max = maxHeight.toDp())
|
||||
.align(Alignment.TopStart),
|
||||
)
|
||||
DevtoolsOverlay(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -565,4 +614,108 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
updateSoftInputWindowLayoutParameters()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ComposeExtractedLandscapeInputView(eet: ExtractEditText?) : FrameLayout(this) {
|
||||
val composeView: ComposeView
|
||||
val extractEditText: ExtractEditText
|
||||
|
||||
init {
|
||||
isHapticFeedbackEnabled = true
|
||||
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
|
||||
extractEditText = (eet ?: ExtractEditText(context)).also {
|
||||
it.id = android.R.id.inputExtractEditText
|
||||
it.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
it.background = null
|
||||
it.gravity = Gravity.TOP
|
||||
it.isVerticalScrollBarEnabled = true
|
||||
}
|
||||
addView(extractEditText)
|
||||
|
||||
composeView = ComposeView(context).also { it.setContent { Content() } }
|
||||
addView(composeView)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Content() {
|
||||
ProvideLocalizedResources(resourcesContext, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
FlorisImeTheme {
|
||||
val layoutStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputLayout)
|
||||
val fieldStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputField)
|
||||
val actionStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputAction)
|
||||
val activeEditorInfo by editorInstance.activeInfoFlow.collectAsState()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.snyggBackground(layoutStyle, FlorisImeTheme.fallbackSurfaceColor()),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val fieldColor = fieldStyle.foreground.solidColor(FlorisImeTheme.fallbackContentColor())
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.snyggShadow(fieldStyle)
|
||||
.snyggBorder(fieldStyle)
|
||||
.snyggBackground(fieldStyle),
|
||||
factory = { extractEditText },
|
||||
update = { view ->
|
||||
view.background = null
|
||||
view.backgroundTintList = null
|
||||
view.foregroundTintList = null
|
||||
view.setTextColor(fieldColor.toArgb())
|
||||
view.setHintTextColor(fieldColor.copy(fieldColor.alpha * 0.6f).toArgb())
|
||||
view.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
fieldStyle.fontSize.spSize(default = 16.sp).value,
|
||||
)
|
||||
},
|
||||
)
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
if (activeEditorInfo.extractedActionId != 0) {
|
||||
currentInputConnection?.performEditorAction(activeEditorInfo.extractedActionId)
|
||||
} else {
|
||||
editorInstance.performEnterAction(activeEditorInfo.imeOptions.action)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
text = activeEditorInfo.extractedActionLabel
|
||||
?: getTextForImeAction(activeEditorInfo.imeOptions.action.toInt())
|
||||
?: "ACTION",
|
||||
shape = actionStyle.shape.shape(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = actionStyle.background.solidColor(FlorisImeTheme.fallbackContentColor()),
|
||||
contentColor = actionStyle.foreground.solidColor(FlorisImeTheme.fallbackSurfaceColor()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAccessibilityClassName(): CharSequence {
|
||||
return javaClass.name
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
removeView(extractEditText)
|
||||
super.onAttachedToWindow()
|
||||
try {
|
||||
(parent as LinearLayout).let { extractEditLayout ->
|
||||
extractEditLayout.layoutParams = LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
).also { it.setMargins(0, 0, 0, 0) }
|
||||
extractEditLayout.setPadding(0, 0, 0, 0)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
flogError { e.message.toString() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,13 @@ 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.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.debug.LogTopic
|
||||
import dev.patrickgold.florisboard.debug.flogInfo
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingLanguageMode
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingService
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogInfo
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class FlorisSpellCheckerService : SpellCheckerService() {
|
||||
@@ -14,11 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.prefs
|
||||
package dev.patrickgold.florisboard.app
|
||||
|
||||
import dev.patrickgold.florisboard.app.AppTheme
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.DisplayColorsAs
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.DisplayKbdAfterDialogs
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import dev.patrickgold.florisboard.app.settings.theme.DisplayColorsAs
|
||||
import dev.patrickgold.florisboard.app.settings.theme.DisplayKbdAfterDialogs
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
@@ -36,11 +38,14 @@ import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SmartbarRowType
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeMode
|
||||
import dev.patrickgold.florisboard.ime.theme.extCoreTheme
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.snygg.SnyggLevel
|
||||
import dev.patrickgold.florisboard.util.VersionName
|
||||
import dev.patrickgold.florisboard.lib.android.isOrientationPortrait
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.lib.snygg.SnyggLevel
|
||||
import dev.patrickgold.florisboard.lib.util.VersionName
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceModel
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
|
||||
fun florisPreferenceModel() = JetPref.getOrCreatePreferenceModel(AppPrefs::class, ::AppPrefs)
|
||||
|
||||
@@ -135,12 +140,16 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
key = "devtools__show_primary_clip",
|
||||
default = false,
|
||||
)
|
||||
val showInputStateOverlay = boolean(
|
||||
key = "devtools__show_input_state_overlay",
|
||||
default = false,
|
||||
)
|
||||
val showSpellingOverlay = boolean(
|
||||
key = "devtools__show_spelling_overlay",
|
||||
default = false,
|
||||
)
|
||||
val overrideWordSuggestionsMinHeapRestriction = boolean(
|
||||
key = "devtools__override_word_suggestions_min_heap_restriction",
|
||||
val showKeyTouchBoundaries = boolean(
|
||||
key = "devtools__show_touch_boundaries",
|
||||
default = false,
|
||||
)
|
||||
}
|
||||
@@ -177,7 +186,7 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
)
|
||||
val spaceBarSwipeUp = enum(
|
||||
key = "gestures__space_bar_swipe_up",
|
||||
default = SwipeAction.SWITCH_TO_CLIPBOARD_CONTEXT,
|
||||
default = SwipeAction.NO_ACTION,
|
||||
)
|
||||
val spaceBarSwipeLeft = enum(
|
||||
key = "gestures__space_bar_swipe_left",
|
||||
@@ -195,9 +204,13 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
key = "gestures__delete_key_swipe_left",
|
||||
default = SwipeAction.DELETE_CHARACTERS_PRECISELY,
|
||||
)
|
||||
val deleteKeyLongPress = enum(
|
||||
key = "gestures__delete_key_long_press",
|
||||
default = SwipeAction.DELETE_CHARACTER,
|
||||
)
|
||||
val swipeDistanceThreshold = int(
|
||||
key = "gestures__swipe_distance_threshold",
|
||||
default = 36,
|
||||
default = 32,
|
||||
)
|
||||
val swipeVelocityThreshold = int(
|
||||
key = "gestures__swipe_velocity_threshold",
|
||||
@@ -227,6 +240,10 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
key = "glide__preview_refresh_delay",
|
||||
default = 150,
|
||||
)
|
||||
val immediateBackspaceDeletesWord = boolean(
|
||||
key = "glide__immediate_backspace_deletes_word",
|
||||
default = true,
|
||||
)
|
||||
}
|
||||
|
||||
val inputFeedback = InputFeedback()
|
||||
@@ -309,7 +326,7 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
val internal = Internal()
|
||||
inner class Internal {
|
||||
val homeIsBetaToolboxCollapsed = boolean(
|
||||
key = "internal__home_is_beta_toolbox_collapsed_0314release",
|
||||
key = "internal__home_is_beta_toolbox_collapsed_0316beta01",
|
||||
default = false,
|
||||
)
|
||||
val isImeSetUp = boolean(
|
||||
@@ -438,6 +455,24 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
mergeHintPopups = mergeHintPopupsEnabled.get(),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun fontSizeMultiplier(): Float {
|
||||
val configuration = LocalConfiguration.current
|
||||
val oneHandedMode by oneHandedMode.observeAsState()
|
||||
val oneHandedModeFactor by oneHandedModeScaleFactor.observeAsTransformingState { it / 100.0f }
|
||||
val fontSizeMultiplierBase by if (configuration.isOrientationPortrait()) {
|
||||
fontSizeMultiplierPortrait
|
||||
} else {
|
||||
fontSizeMultiplierLandscape
|
||||
}.observeAsTransformingState { it / 100.0f }
|
||||
val fontSizeMultiplier = fontSizeMultiplierBase * if (oneHandedMode != OneHandedMode.OFF && configuration.isOrientationPortrait()) {
|
||||
oneHandedModeFactor
|
||||
} else {
|
||||
1.0f
|
||||
}
|
||||
return fontSizeMultiplier
|
||||
}
|
||||
}
|
||||
|
||||
val localization = Localization()
|
||||
@@ -41,21 +41,19 @@ import com.google.accompanist.insets.ProvideWindowInsets
|
||||
import com.google.accompanist.insets.navigationBarsWithImePadding
|
||||
import com.google.accompanist.insets.statusBarsPadding
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.res.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.LocalPreviewFieldController
|
||||
import dev.patrickgold.florisboard.app.ui.components.PreviewKeyboardField
|
||||
import dev.patrickgold.florisboard.app.ui.components.SystemUiApp
|
||||
import dev.patrickgold.florisboard.app.ui.components.rememberPreviewFieldController
|
||||
import dev.patrickgold.florisboard.app.ui.theme.FlorisAppTheme
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.android.hideAppIcon
|
||||
import dev.patrickgold.florisboard.common.android.setLocale
|
||||
import dev.patrickgold.florisboard.common.android.showAppIcon
|
||||
import dev.patrickgold.florisboard.util.AppVersionUtils
|
||||
import dev.patrickgold.florisboard.app.apptheme.FlorisAppTheme
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.lib.android.hideAppIcon
|
||||
import dev.patrickgold.florisboard.lib.android.setLocale
|
||||
import dev.patrickgold.florisboard.lib.android.showAppIcon
|
||||
import dev.patrickgold.florisboard.lib.compose.LocalPreviewFieldController
|
||||
import dev.patrickgold.florisboard.lib.compose.PreviewKeyboardField
|
||||
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.lib.compose.SystemUiApp
|
||||
import dev.patrickgold.florisboard.lib.compose.rememberPreviewFieldController
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.util.AppVersionUtils
|
||||
import dev.patrickgold.jetpref.datastore.ui.ProvideDefaultDialogPrefStrings
|
||||
|
||||
enum class AppTheme(val id: String) {
|
||||
@@ -14,51 +14,51 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui
|
||||
package dev.patrickgold.florisboard.app
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import dev.patrickgold.florisboard.app.ui.devtools.AndroidLocalesScreen
|
||||
import dev.patrickgold.florisboard.app.ui.devtools.AndroidSettingsScreen
|
||||
import dev.patrickgold.florisboard.app.ui.devtools.DevtoolsScreen
|
||||
import dev.patrickgold.florisboard.app.ui.ext.ExtensionEditScreen
|
||||
import dev.patrickgold.florisboard.app.ui.ext.ExtensionExportScreen
|
||||
import dev.patrickgold.florisboard.app.ui.ext.ExtensionImportScreen
|
||||
import dev.patrickgold.florisboard.app.ui.ext.ExtensionImportScreenType
|
||||
import dev.patrickgold.florisboard.app.ui.ext.ExtensionViewScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.HomeScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.about.AboutScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.about.ProjectLicenseScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.about.ThirdPartyLicensesScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.advanced.AdvancedScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.advanced.BackupScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.advanced.RestoreScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.clipboard.ClipboardScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.dictionary.DictionaryScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.dictionary.UserDictionaryScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.dictionary.UserDictionaryType
|
||||
import dev.patrickgold.florisboard.app.ui.settings.gestures.GesturesScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.keyboard.InputFeedbackScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.keyboard.KeyboardScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.localization.LocalizationScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.localization.SelectLocaleScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.localization.SubtypeEditorScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.media.MediaScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.smartbar.SmartbarScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.spelling.ImportSpellingArchiveScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.spelling.ManageSpellingDictsScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.spelling.SpellingInfoScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.spelling.SpellingScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.ThemeScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.ThemeManagerScreen
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.ThemeManagerScreenAction
|
||||
import dev.patrickgold.florisboard.app.ui.settings.typing.TypingScreen
|
||||
import dev.patrickgold.florisboard.app.ui.setup.SetupScreen
|
||||
import dev.patrickgold.florisboard.app.ui.splash.SplashScreen
|
||||
import dev.patrickgold.florisboard.common.kotlin.curlyFormat
|
||||
import dev.patrickgold.florisboard.app.devtools.AndroidLocalesScreen
|
||||
import dev.patrickgold.florisboard.app.devtools.AndroidSettingsScreen
|
||||
import dev.patrickgold.florisboard.app.devtools.DevtoolsScreen
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionEditScreen
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionExportScreen
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreen
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionViewScreen
|
||||
import dev.patrickgold.florisboard.app.settings.HomeScreen
|
||||
import dev.patrickgold.florisboard.app.settings.about.AboutScreen
|
||||
import dev.patrickgold.florisboard.app.settings.about.ProjectLicenseScreen
|
||||
import dev.patrickgold.florisboard.app.settings.about.ThirdPartyLicensesScreen
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.AdvancedScreen
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.BackupScreen
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.RestoreScreen
|
||||
import dev.patrickgold.florisboard.app.settings.clipboard.ClipboardScreen
|
||||
import dev.patrickgold.florisboard.app.settings.dictionary.DictionaryScreen
|
||||
import dev.patrickgold.florisboard.app.settings.dictionary.UserDictionaryScreen
|
||||
import dev.patrickgold.florisboard.app.settings.dictionary.UserDictionaryType
|
||||
import dev.patrickgold.florisboard.app.settings.gestures.GesturesScreen
|
||||
import dev.patrickgold.florisboard.app.settings.keyboard.InputFeedbackScreen
|
||||
import dev.patrickgold.florisboard.app.settings.keyboard.KeyboardScreen
|
||||
import dev.patrickgold.florisboard.app.settings.localization.LocalizationScreen
|
||||
import dev.patrickgold.florisboard.app.settings.localization.SelectLocaleScreen
|
||||
import dev.patrickgold.florisboard.app.settings.localization.SubtypeEditorScreen
|
||||
import dev.patrickgold.florisboard.app.settings.media.MediaScreen
|
||||
import dev.patrickgold.florisboard.app.settings.smartbar.SmartbarScreen
|
||||
import dev.patrickgold.florisboard.app.settings.spelling.ImportSpellingArchiveScreen
|
||||
import dev.patrickgold.florisboard.app.settings.spelling.ManageSpellingDictsScreen
|
||||
import dev.patrickgold.florisboard.app.settings.spelling.SpellingInfoScreen
|
||||
import dev.patrickgold.florisboard.app.settings.spelling.SpellingScreen
|
||||
import dev.patrickgold.florisboard.app.settings.theme.ThemeManagerScreen
|
||||
import dev.patrickgold.florisboard.app.settings.theme.ThemeManagerScreenAction
|
||||
import dev.patrickgold.florisboard.app.settings.theme.ThemeScreen
|
||||
import dev.patrickgold.florisboard.app.settings.typing.TypingScreen
|
||||
import dev.patrickgold.florisboard.app.setup.SetupScreen
|
||||
import dev.patrickgold.florisboard.app.splash.SplashScreen
|
||||
import dev.patrickgold.florisboard.lib.kotlin.curlyFormat
|
||||
|
||||
@Suppress("FunctionName")
|
||||
object Routes {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.theme
|
||||
package dev.patrickgold.florisboard.app.apptheme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.theme
|
||||
package dev.patrickgold.florisboard.app.apptheme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Shapes
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.theme
|
||||
package dev.patrickgold.florisboard.app.apptheme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.theme
|
||||
package dev.patrickgold.florisboard.app.apptheme
|
||||
|
||||
import androidx.compose.material.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.devtools
|
||||
package dev.patrickgold.florisboard.app.devtools
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -23,12 +23,15 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
@@ -39,17 +42,22 @@ fun AndroidLocalesScreen() = FlorisScreen {
|
||||
val availableLocales = remember { Locale.getAvailableLocales().sortedBy { it.toLanguageTag() } }
|
||||
|
||||
content {
|
||||
val displayLanguageNamesIn by prefs.localization.displayLanguageNamesIn.observeAsState()
|
||||
|
||||
SelectionContainer(modifier = Modifier.fillMaxWidth()) {
|
||||
LazyColumn {
|
||||
items(availableLocales) {
|
||||
items(availableLocales) { locale ->
|
||||
Row {
|
||||
Text(
|
||||
text = it.toLanguageTag().padEnd(12),
|
||||
text = locale.toLanguageTag().padEnd(12),
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.weight(1.0f),
|
||||
text = it.getDisplayName(it),
|
||||
text = when (displayLanguageNamesIn) {
|
||||
DisplayLanguageNamesIn.SYSTEM_LOCALE -> locale.displayName
|
||||
DisplayLanguageNamesIn.NATIVE_LOCALE -> locale.getDisplayName(locale)
|
||||
},
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.devtools
|
||||
package dev.patrickgold.florisboard.app.devtools
|
||||
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -27,9 +27,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.common.android.AndroidSettings
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidSettings
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||
@@ -14,17 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.devtools
|
||||
package dev.patrickgold.florisboard.app.devtools
|
||||
|
||||
import android.view.textservice.SuggestionsInfo
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.Text
|
||||
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
|
||||
@@ -37,10 +39,11 @@ 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.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.common.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.spellingManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import java.text.SimpleDateFormat
|
||||
@@ -50,14 +53,11 @@ private val CardBackground = Color.Black.copy(0.6f)
|
||||
private val DateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", FlorisLocale.default().base)
|
||||
|
||||
@Composable
|
||||
fun DevtoolsOverlay(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val context = LocalContext.current
|
||||
val clipboardManager by context.clipboardManager()
|
||||
|
||||
val showPrimaryClip by prefs.devtools.showPrimaryClip.observeAsState()
|
||||
val showInputStateOverlay by prefs.devtools.showInputStateOverlay.observeAsState()
|
||||
val showSpellingOverlay by prefs.devtools.showSpellingOverlay.observeAsState()
|
||||
|
||||
CompositionLocalProvider(
|
||||
@@ -66,11 +66,10 @@ fun DevtoolsOverlay(
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
if (showPrimaryClip) {
|
||||
val primaryClip by clipboardManager.primaryClip.observeAsState()
|
||||
Text(
|
||||
text = primaryClip.toString(),
|
||||
color = Color.White,
|
||||
)
|
||||
DevtoolsClipboardOverlay()
|
||||
}
|
||||
if (showInputStateOverlay) {
|
||||
DevtoolsInputStateOverlay()
|
||||
}
|
||||
if (showSpellingOverlay) {
|
||||
DevtoolsSpellingOverlay()
|
||||
@@ -79,6 +78,46 @@ fun DevtoolsOverlay(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsClipboardOverlay() {
|
||||
val context = LocalContext.current
|
||||
val clipboardManager by context.clipboardManager()
|
||||
|
||||
DevtoolsOverlayBox(title = "Clipboard overlay") {
|
||||
val primaryClip by clipboardManager.primaryClip.observeAsState()
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 8.dp, start = 8.dp, end = 8.dp),
|
||||
text = primaryClip.toString(),
|
||||
color = Color.White,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsInputStateOverlay() {
|
||||
val context = LocalContext.current
|
||||
val editorInstance by context.editorInstance()
|
||||
|
||||
val info by editorInstance.activeInfoFlow.collectAsState()
|
||||
val content by editorInstance.activeContentFlow.collectAsState()
|
||||
val selection = content.selection
|
||||
|
||||
DevtoolsOverlayBox(title = "Input state overlay") {
|
||||
DevtoolsSubGroup(title = "EditorInfo") {
|
||||
DevtoolsText(text = "Type=${info.inputAttributes.type} Variation=${info.inputAttributes.variation} IsRich=${info.isRichInputEditor}")
|
||||
DevtoolsText(text = "InitialSelection: ${info.initialSelection}")
|
||||
}
|
||||
DevtoolsSubGroup(title = "EditorContent") {
|
||||
DevtoolsText(text = "Selection: { start=${selection.start}, end=${selection.end} }")
|
||||
DevtoolsText(text = "Before: \"${content.textBeforeSelection}\"")
|
||||
DevtoolsText(text = "Selected: \"${content.selectedText}\"")
|
||||
DevtoolsText(text = "After: \"${content.textAfterSelection}\"")
|
||||
DevtoolsText(text = "ComposingWord: ${content.composing}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsSpellingOverlay() {
|
||||
val context = LocalContext.current
|
||||
@@ -87,18 +126,8 @@ private fun DevtoolsSpellingOverlay() {
|
||||
val debugOverlayVersion by spellingManager.debugOverlayVersion.observeAsNonNullState()
|
||||
val suggestionsInfos = remember(debugOverlayVersion) { spellingManager.debugOverlaySuggestionsInfos.snapshot() }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.background(CardBackground),
|
||||
) {
|
||||
val sortedEntries = suggestionsInfos.entries.sortedByDescending { it.key }
|
||||
Text(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
text = "Spelling overlay (${sortedEntries.size})",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
val sortedEntries = suggestionsInfos.entries.sortedByDescending { it.key }
|
||||
DevtoolsOverlayBox(title = "Spelling overlay (${sortedEntries.size})") {
|
||||
for ((timestamp, wordInfoPair) in sortedEntries) {
|
||||
val (word, info) = wordInfoPair
|
||||
val isTypo = (info.suggestionsAttributes and SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0
|
||||
@@ -131,3 +160,47 @@ private fun DevtoolsSpellingOverlay() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsOverlayBox(
|
||||
title: String,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.background(CardBackground),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
text = title,
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsSubGroup(
|
||||
title: String,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
text = title,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 12.sp,
|
||||
)
|
||||
Column(modifier = Modifier.padding(start = 12.dp, bottom = 8.dp), content = content)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsText(text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
)
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.devtools
|
||||
package dev.patrickgold.florisboard.app.devtools
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -22,13 +22,13 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisConfirmDeleteDialog
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.common.android.AndroidSettings
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
import dev.patrickgold.florisboard.ime.dictionary.FlorisUserDictionaryDatabase
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidSettings
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisConfirmDeleteDialog
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
|
||||
@@ -66,17 +66,22 @@ fun DevtoolsScreen() = FlorisScreen {
|
||||
summary = stringRes(R.string.devtools__show_primary_clip__summary),
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.devtools.showInputStateOverlay,
|
||||
title = stringRes(R.string.devtools__show_input_state_overlay__label),
|
||||
summary = stringRes(R.string.devtools__show_input_state_overlay__summary),
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.devtools.showSpellingOverlay,
|
||||
title = stringRes(R.string.devtools__show_spelling_overlay__label),
|
||||
summary = stringRes(R.string.devtools__show_spelling_overlay__summary),
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
// TODO: remove this preference once word suggestions are re-implemented in 0.3.15/16
|
||||
SwitchPreference(
|
||||
prefs.devtools.overrideWordSuggestionsMinHeapRestriction,
|
||||
title = "Override min heap size restriction for word suggestions",
|
||||
summary = "This allows you to use word suggestions even if your heap size is not intended for it and can break FlorisBoard",
|
||||
prefs.devtools.showKeyTouchBoundaries,
|
||||
title = stringRes(R.string.devtools__show_key_touch_boundaries__label),
|
||||
summary = stringRes(R.string.devtools__show_key_touch_boundaries__summary),
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
Preference(
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -37,14 +37,14 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisTextButton
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionComponent
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponent
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMeta
|
||||
|
||||
@Composable
|
||||
fun ExtensionComponentNoneFoundView() {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
@@ -44,24 +44,11 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisInfoCard
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisUnsavedChangesDialog
|
||||
import dev.patrickgold.florisboard.app.ui.components.autoMirrorForRtl
|
||||
import dev.patrickgold.florisboard.app.ui.components.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.settings.advanced.RadioListItem
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.DialogProperty
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.ThemeEditorScreen
|
||||
import dev.patrickgold.florisboard.app.ui.theme.outline
|
||||
import dev.patrickgold.florisboard.app.apptheme.outline
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.RadioListItem
|
||||
import dev.patrickgold.florisboard.app.settings.theme.DialogProperty
|
||||
import dev.patrickgold.florisboard.app.settings.theme.ThemeEditorScreen
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.common.ValidationResult
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.common.rememberValidationResult
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardExtension
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingExtension
|
||||
@@ -70,23 +57,36 @@ import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentEditor
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentImpl
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionEditor
|
||||
import dev.patrickgold.florisboard.res.FlorisRef
|
||||
import dev.patrickgold.florisboard.res.ZipUtils
|
||||
import dev.patrickgold.florisboard.res.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.res.ext.Extension
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionComponent
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionDefaults
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionEditor
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionJsonConfig
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionMaintainer
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionValidation
|
||||
import dev.patrickgold.florisboard.res.ext.validate
|
||||
import dev.patrickgold.florisboard.res.io.subFile
|
||||
import dev.patrickgold.florisboard.res.io.writeJson
|
||||
import dev.patrickgold.florisboard.snygg.SnyggStylesheetJsonConfig
|
||||
import dev.patrickgold.florisboard.lib.ValidationResult
|
||||
import dev.patrickgold.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisInfoCard
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisUnsavedChangesDialog
|
||||
import dev.patrickgold.florisboard.lib.compose.autoMirrorForRtl
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.ext.Extension
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponent
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionDefaults
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionEditor
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionJsonConfig
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMaintainer
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionValidation
|
||||
import dev.patrickgold.florisboard.lib.ext.validate
|
||||
import dev.patrickgold.florisboard.lib.io.FlorisRef
|
||||
import dev.patrickgold.florisboard.lib.io.ZipUtils
|
||||
import dev.patrickgold.florisboard.lib.io.subFile
|
||||
import dev.patrickgold.florisboard.lib.io.writeJson
|
||||
import dev.patrickgold.florisboard.lib.rememberValidationResult
|
||||
import dev.patrickgold.florisboard.lib.snygg.SnyggStylesheetJsonConfig
|
||||
import dev.patrickgold.florisboard.themeManager
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -22,11 +22,11 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.res.ext.Extension
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionDefaults
|
||||
import dev.patrickgold.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
|
||||
|
||||
@Composable
|
||||
fun ExtensionExportScreen(id: String) {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import android.text.format.Formatter
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -45,24 +45,24 @@ import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisBulletSpacer
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.common.kotlin.resultOk
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardExtension
|
||||
import dev.patrickgold.florisboard.ime.nlp.NATIVE_NULLPTR
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingExtension
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtension
|
||||
import dev.patrickgold.florisboard.res.FileRegistry
|
||||
import dev.patrickgold.florisboard.res.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisBulletSpacer
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
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 dev.patrickgold.florisboard.lib.kotlin.resultOk
|
||||
|
||||
enum class ExtensionImportScreenType(
|
||||
val id: String,
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisChip
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisChip
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -22,8 +22,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.res.ext.Extension
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.lib.ext.Extension
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
|
||||
@Composable
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
|
||||
@Composable
|
||||
fun ExtensionListScreen() = FlorisScreen {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -22,16 +22,16 @@ import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisChip
|
||||
import dev.patrickgold.florisboard.common.android.launchUrl
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionMaintainer
|
||||
import dev.patrickgold.florisboard.lib.android.launchUrl
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisChip
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMaintainer
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -23,8 +23,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
|
||||
@Composable
|
||||
internal fun ExtensionNotFoundScreen(id: String) = FlorisScreen {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -44,21 +44,21 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisConfirmDeleteDialog
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisHyperlinkText
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtension
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentImpl
|
||||
import dev.patrickgold.florisboard.res.FlorisRef
|
||||
import dev.patrickgold.florisboard.res.ext.Extension
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionMaintainer
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisConfirmDeleteDialog
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisHyperlinkText
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
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
|
||||
|
||||
@Composable
|
||||
fun ExtensionViewScreen(id: String) {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.ext
|
||||
package dev.patrickgold.florisboard.app.ext
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings
|
||||
package dev.patrickgold.florisboard.app.settings
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -38,12 +38,14 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisErrorCard
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisWarningCard
|
||||
import dev.patrickgold.florisboard.common.InputMethodUtils
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.lib.android.launchUrl
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisErrorCard
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisWarningCard
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.util.InputMethodUtils
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
|
||||
@@ -81,7 +83,7 @@ fun HomeScreen() = FlorisScreen {
|
||||
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = "Note on the new Settings UI",
|
||||
text = "Welcome to the 0.3.16 beta series!",
|
||||
style = MaterialTheme.typography.subtitle1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
@@ -98,8 +100,9 @@ fun HomeScreen() = FlorisScreen {
|
||||
}
|
||||
}
|
||||
if (!isCollapsed) {
|
||||
Text("Welcome to the new Settings of FlorisBoard!\n")
|
||||
Text("It has been quite a long time since 0.3.13, but since then a lot has changed. FlorisBoard has undergone a major overhaul and now uses a completely new UI library, backend logic and also the Settings have been completely revamped. A big thanks goes to all my beta testers who continuously provided feedback and tested things out, this made the development much more interactive and better!\n")
|
||||
Text("The 0.3.16 beta series focuses on preparing the keyboard for word suggestions in 0.4.0, getting rid of the input lag and improve input connection handling. Most work is already done, now I am focusing on fixing introduced bugs and generally fixing a lot of bugs to improve the stability of this keyboard.\n")
|
||||
Text("If you have general feedback on this rework or want to report a newly broken/buggy input for a specific app (or all apps), please make sure to post your feedback in this thread:\n")
|
||||
FlorisButton(onClick = { context.launchUrl("https://github.com/florisboard/florisboard/discussions/1827") }, text = "Open feedback thread")
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text("Note that this release does not contain support for word suggestions (will show the current word plus numbers as a placeholder).", color = Color.Red)
|
||||
Text("Please DO NOT file an issue for this. It is already more than known and a major goal for implementation in 0.4.0. Thank you!\n")
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.about
|
||||
package dev.patrickgold.florisboard.app.settings.about
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -33,13 +33,13 @@ import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisCanvasIcon
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.common.android.launchUrl
|
||||
import dev.patrickgold.florisboard.common.android.stringRes
|
||||
import dev.patrickgold.florisboard.lib.android.launchUrl
|
||||
import dev.patrickgold.florisboard.lib.android.stringRes
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisCanvasIcon
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
|
||||
@Composable
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.about
|
||||
package dev.patrickgold.florisboard.app.settings.about
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
@@ -28,12 +28,12 @@ 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.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisVerticalScroll
|
||||
import dev.patrickgold.florisboard.assetManager
|
||||
import dev.patrickgold.florisboard.res.FlorisRef
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.florisVerticalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.io.FlorisRef
|
||||
|
||||
@Composable
|
||||
fun ProjectLicenseScreen() = FlorisScreen {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.about
|
||||
package dev.patrickgold.florisboard.app.settings.about
|
||||
|
||||
import android.webkit.URLUtil
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -31,10 +31,10 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisScrollbar
|
||||
import dev.patrickgold.florisboard.common.android.launchUrl
|
||||
import dev.patrickgold.florisboard.lib.android.launchUrl
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||
@@ -14,19 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.advanced
|
||||
package dev.patrickgold.florisboard.app.settings.advanced
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.AppTheme
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
@@ -115,6 +115,7 @@ fun AdvancedScreen() = FlorisScreen {
|
||||
"tr",
|
||||
"uk",
|
||||
"zgh",
|
||||
"zh-CN",
|
||||
).map { languageTag ->
|
||||
if (languageTag == "auto") {
|
||||
entry(
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.advanced
|
||||
package dev.patrickgold.florisboard.app.settings.advanced
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -33,22 +33,22 @@ import androidx.core.content.FileProvider
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.rippleClickable
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.common.android.writeFromFile
|
||||
import dev.patrickgold.florisboard.res.FileRegistry
|
||||
import dev.patrickgold.florisboard.res.ZipUtils
|
||||
import dev.patrickgold.florisboard.res.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.res.io.subDir
|
||||
import dev.patrickgold.florisboard.res.io.subFile
|
||||
import dev.patrickgold.florisboard.res.io.writeJson
|
||||
import dev.patrickgold.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.android.writeFromFile
|
||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.rippleClickable
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.lib.io.FileRegistry
|
||||
import dev.patrickgold.florisboard.lib.io.ZipUtils
|
||||
import dev.patrickgold.florisboard.lib.io.subDir
|
||||
import dev.patrickgold.florisboard.lib.io.subFile
|
||||
import dev.patrickgold.florisboard.lib.io.writeJson
|
||||
import dev.patrickgold.jetpref.datastore.jetprefDatastoreDir
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import kotlinx.serialization.SerialName
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.advanced
|
||||
package dev.patrickgold.florisboard.app.settings.advanced
|
||||
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@@ -41,30 +41,30 @@ import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.CardDefaults
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.common.android.readToFile
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.res.FileRegistry
|
||||
import dev.patrickgold.florisboard.res.ZipUtils
|
||||
import dev.patrickgold.florisboard.res.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.res.io.deleteContentsRecursively
|
||||
import dev.patrickgold.florisboard.res.io.readJson
|
||||
import dev.patrickgold.florisboard.res.io.subDir
|
||||
import dev.patrickgold.florisboard.res.io.subFile
|
||||
import dev.patrickgold.florisboard.lib.android.readToFile
|
||||
import dev.patrickgold.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.compose.CardDefaults
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
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.florisboard.lib.io.deleteContentsRecursively
|
||||
import dev.patrickgold.florisboard.lib.io.readJson
|
||||
import dev.patrickgold.florisboard.lib.io.subDir
|
||||
import dev.patrickgold.florisboard.lib.io.subFile
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.FileNotFoundException
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
@@ -84,6 +84,7 @@ 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()
|
||||
@@ -108,7 +109,11 @@ fun RestoreScreen() = FlorisScreen {
|
||||
workspace.zipFile = workspace.inputDir.subFile(Restore.BACKUP_ARCHIVE_FILE_NAME)
|
||||
context.contentResolver.readToFile(uri, workspace.zipFile)
|
||||
ZipUtils.unzip(workspace.zipFile, workspace.outputDir)
|
||||
workspace.metadata = workspace.outputDir.subFile(Backup.METADATA_JSON_NAME).readJson()
|
||||
workspace.metadata = try {
|
||||
workspace.outputDir.subFile(Backup.METADATA_JSON_NAME).readJson()
|
||||
} catch (e: FileNotFoundException) {
|
||||
error("Invalid archive: either backup_metadata.json is missing or file is not a ZIP archive.")
|
||||
}
|
||||
workspace.restoreWarningId = when {
|
||||
workspace.metadata.versionCode != BuildConfig.VERSION_CODE -> {
|
||||
R.string.backup_and_restore__restore__metadata_warn_different_version
|
||||
@@ -132,7 +137,6 @@ fun RestoreScreen() = FlorisScreen {
|
||||
)
|
||||
|
||||
suspend fun performRestore() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val workspace = restoreWorkspace!!
|
||||
val shouldReset = restoreMode == Restore.Mode.ERASE_AND_OVERWRITE
|
||||
if (restoreFilesSelector.jetprefDatastore) {
|
||||
@@ -228,9 +232,7 @@ fun RestoreScreen() = FlorisScreen {
|
||||
FlorisOutlinedButton(
|
||||
onClick = {
|
||||
runCatching {
|
||||
restoreDataFromFileSystemLauncher.launch(
|
||||
FileRegistry.BackupArchive.mediaType
|
||||
)
|
||||
restoreDataFromFileSystemLauncher.launch("*/*")
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(R.string.backup_and_restore__restore__failure, "error_message" to error.localizedMessage)
|
||||
}
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.clipboard
|
||||
package dev.patrickgold.florisboard.app.settings.clipboard
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.pluralsRes
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.pluralsRes
|
||||
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.PreferenceGroup
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.dictionary
|
||||
package dev.patrickgold.florisboard.app.settings.dictionary
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.dictionary
|
||||
package dev.patrickgold.florisboard.app.settings.dictionary
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -43,23 +43,23 @@ import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.rippleClickable
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.DialogProperty
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.common.android.launchActivity
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.common.android.stringRes
|
||||
import dev.patrickgold.florisboard.common.rememberValidationResult
|
||||
import dev.patrickgold.florisboard.app.settings.theme.DialogProperty
|
||||
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
|
||||
import dev.patrickgold.florisboard.ime.dictionary.FREQUENCY_MAX
|
||||
import dev.patrickgold.florisboard.ime.dictionary.FREQUENCY_MIN
|
||||
import dev.patrickgold.florisboard.ime.dictionary.UserDictionaryDao
|
||||
import dev.patrickgold.florisboard.ime.dictionary.UserDictionaryEntry
|
||||
import dev.patrickgold.florisboard.ime.dictionary.UserDictionaryValidation
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.android.launchActivity
|
||||
import dev.patrickgold.florisboard.lib.android.showLongToast
|
||||
import dev.patrickgold.florisboard.lib.android.stringRes
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.rippleClickable
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.rememberValidationResult
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -14,17 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.gestures
|
||||
package dev.patrickgold.florisboard.app.settings.gestures
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisInfoCard
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisInfoCard
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
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
|
||||
@@ -81,6 +81,12 @@ fun GesturesScreen() = FlorisScreen {
|
||||
stepIncrement = 25,
|
||||
enabledIf = { prefs.glide.enabled isEqualTo true && prefs.glide.showPreview isEqualTo true },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.glide.immediateBackspaceDeletesWord,
|
||||
title = stringRes(R.string.pref__glide__immediate_backspace_deletes_word__label),
|
||||
summary = stringRes(R.string.pref__glide__immediate_backspace_deletes_word__summary),
|
||||
enabledIf = { prefs.glide.enabled isEqualTo true },
|
||||
)
|
||||
}
|
||||
|
||||
PreferenceGroup(title = stringRes(R.string.pref__gestures__general_title)) {
|
||||
@@ -139,6 +145,11 @@ fun GesturesScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.pref__gestures__delete_key_swipe_left__label),
|
||||
entries = SwipeAction.deleteSwipeListEntries(),
|
||||
)
|
||||
ListPreference(
|
||||
prefs.gestures.deleteKeyLongPress,
|
||||
title = stringRes(R.string.pref__gestures__delete_key_long_press__label),
|
||||
entries = SwipeAction.deleteLongPressListEntries(),
|
||||
)
|
||||
DialogSliderPreference(
|
||||
prefs.gestures.swipeVelocityThreshold,
|
||||
title = stringRes(R.string.pref__gestures__swipe_velocity_threshold__label),
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.keyboard
|
||||
package dev.patrickgold.florisboard.app.settings.keyboard
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.ime.keyboard.InputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.input.InputFeedbackController
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
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.PreferenceGroup
|
||||
@@ -14,18 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.keyboard
|
||||
package dev.patrickgold.florisboard.app.settings.keyboard
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
|
||||
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
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
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.localization
|
||||
package dev.patrickgold.florisboard.app.settings.localization
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.ExtendedFloatingActionButton
|
||||
@@ -28,14 +28,14 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisWarningCard
|
||||
import dev.patrickgold.florisboard.common.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LayoutType
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisWarningCard
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.localization
|
||||
package dev.patrickgold.florisboard.app.settings.localization
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -43,12 +43,12 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisScrollbar
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
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
|
||||
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.localization
|
||||
package dev.patrickgold.florisboard.app.settings.localization
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -52,16 +52,8 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Observer
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.Routes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisButtonBar
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisDropdownLikeButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisDropdownMenu
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.observeAsNonNullState
|
||||
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
|
||||
@@ -71,7 +63,14 @@ import dev.patrickgold.florisboard.ime.keyboard.LayoutArrangementComponent
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LayoutType
|
||||
import dev.patrickgold.florisboard.ime.keyboard.extCorePopupMapping
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
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.stringRes
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
@@ -103,6 +102,7 @@ private class SubtypeEditorState(init: Subtype?) {
|
||||
secondaryLocales = editor.secondaryLocales.value,
|
||||
composer = editor.composer.value,
|
||||
currencySet = editor.currencySet.value,
|
||||
punctuationRule = editor.punctuationRule.value,
|
||||
popupMapping = editor.popupMapping.value,
|
||||
layoutMap = editor.layoutMap.value,
|
||||
)
|
||||
@@ -120,6 +120,7 @@ private class SubtypeEditorState(init: Subtype?) {
|
||||
val secondaryLocales: MutableState<List<FlorisLocale>> = mutableStateOf(init?.secondaryLocales ?: listOf())
|
||||
val composer: MutableState<ExtensionComponentName> = mutableStateOf(init?.composer ?: SelectComponentName)
|
||||
val currencySet: MutableState<ExtensionComponentName> = mutableStateOf(init?.currencySet ?: SelectComponentName)
|
||||
val punctuationRule: MutableState<ExtensionComponentName> = mutableStateOf(init?.punctuationRule ?: SelectComponentName)
|
||||
val popupMapping: MutableState<ExtensionComponentName> = mutableStateOf(init?.popupMapping ?: SelectComponentName)
|
||||
val layoutMap: MutableState<SubtypeLayoutMap> = mutableStateOf(init?.layoutMap ?: SelectLayoutMap)
|
||||
|
||||
@@ -129,6 +130,7 @@ private class SubtypeEditorState(init: Subtype?) {
|
||||
secondaryLocales.value = subtype.secondaryLocales
|
||||
composer.value = subtype.composer
|
||||
currencySet.value = subtype.currencySet
|
||||
punctuationRule.value = subtype.punctuationRule
|
||||
popupMapping.value = subtype.popupMapping
|
||||
layoutMap.value = subtype.layoutMap
|
||||
}
|
||||
@@ -148,7 +150,7 @@ private class SubtypeEditorState(init: Subtype?) {
|
||||
check(layoutMap.value.phone2 != SelectComponentName)
|
||||
Subtype(
|
||||
id.value, primaryLocale.value, secondaryLocales.value, composer.value,
|
||||
currencySet.value, popupMapping.value, layoutMap.value,
|
||||
currencySet.value, punctuationRule.value, popupMapping.value, layoutMap.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -267,17 +269,12 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
val systemLocales = remember {
|
||||
if (AndroidVersion.ATLEAST_API24_N) {
|
||||
val list = mutableListOf<FlorisLocale>()
|
||||
val localeList = configuration.locales
|
||||
for (n in 0 until localeList.size()) {
|
||||
list.add(FlorisLocale.from(localeList.get(n)))
|
||||
}
|
||||
list
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
listOf(FlorisLocale.from(configuration.locale))
|
||||
val list = mutableListOf<FlorisLocale>()
|
||||
val localeList = configuration.locales
|
||||
for (n in 0 until localeList.size()) {
|
||||
list.add(FlorisLocale.from(localeList.get(n)))
|
||||
}
|
||||
list
|
||||
}
|
||||
val suggestedPresets = remember(subtypePresets) {
|
||||
val presets = mutableListOf<SubtypePreset>()
|
||||
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.media
|
||||
package dev.patrickgold.florisboard.app.settings.media
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.pluralsRes
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.pluralsRes
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.smartbar
|
||||
package dev.patrickgold.florisboard.app.settings.smartbar
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SmartbarRowType
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
|
||||
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.spelling
|
||||
package dev.patrickgold.florisboard.app.settings.spelling
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -42,15 +42,15 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisDropdownMenu
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisStep
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisStepLayout
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisStepState
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingExtensionEditor
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownMenu
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisStep
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisStepLayout
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisStepState
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.spellingManager
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||