Compare commits
121 Commits
v0.3.14
...
v0.3.16-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
bfe7852bdf | ||
|
|
45fe2f311e | ||
|
|
f73daa2b00 | ||
|
|
4e8ff9ec14 | ||
|
|
a96fc84fc1 | ||
|
|
e62ddc37dd | ||
|
|
06cfa34a4b | ||
|
|
ef849dfefd | ||
|
|
091d43520e | ||
|
|
95b6b1bbf9 | ||
|
|
021014e870 | ||
|
|
aaa4fbae7a | ||
|
|
78b645d820 | ||
|
|
61bd6752e3 | ||
|
|
e4e10f5c72 |
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "dev.patrickgold.florisboard"
|
||||
minSdk = 23
|
||||
minSdk = 24
|
||||
targetSdk = 31
|
||||
versionCode = 75
|
||||
versionName = "0.3.14"
|
||||
versionCode = 81
|
||||
versionName = "0.3.16"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -66,6 +66,9 @@ android {
|
||||
jniLibs {
|
||||
srcDirs("src/main/icu4c/prebuilt/jniLibs")
|
||||
}
|
||||
java {
|
||||
srcDirs("src/main/kotlin")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +118,7 @@ android {
|
||||
create("beta") // Needed because by default the "beta" BuildType does not exist
|
||||
named("beta").configure {
|
||||
applicationIdSuffix = ".beta"
|
||||
versionNameSuffix = ""
|
||||
versionNameSuffix = "-beta01"
|
||||
proguardFiles.add(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||
|
||||
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_beta")
|
||||
@@ -127,9 +130,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 +161,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("androidx.navigation:navigation-compose:2.4.2")
|
||||
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("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")
|
||||
|
||||
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")
|
||||
|
||||
@@ -105,7 +105,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 +123,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">
|
||||
|
||||
@@ -9,6 +9,18 @@
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
"currencySets": [
|
||||
{
|
||||
"id": "armenian_dram",
|
||||
"label": "Armenian dram (֏)",
|
||||
"slots": [
|
||||
{ "code": 1423, "label": "֏" },
|
||||
{ "code": 36, "label": "$" },
|
||||
{ "code": 8364, "label": "€" },
|
||||
{ "code": 162, "label": "¢" },
|
||||
{ "code": 163, "label": "£" },
|
||||
{ "code": 165, "label": "¥" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "azerbaijani_manat",
|
||||
"label": "Azerbaijani manat (₼)",
|
||||
|
||||
@@ -17,6 +17,26 @@
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:arabic"
|
||||
},
|
||||
{
|
||||
"id": "western_armenian",
|
||||
"label": "Armenian (Western)",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:armenian"
|
||||
},
|
||||
{
|
||||
"id": "eastern_armenian",
|
||||
"label": "Armenian (Eastern)",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:armenian"
|
||||
},
|
||||
{
|
||||
"id": "azerbaijani",
|
||||
"label": "Azerbaijani",
|
||||
"authors": [ "nijatismayilzada" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "azerty",
|
||||
"label": "AZERTY",
|
||||
@@ -72,6 +92,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "colemak_dh",
|
||||
"label": "ColemakDH",
|
||||
"authors": [ "blucin" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "danish",
|
||||
"label": "Danish (QWERTY)",
|
||||
@@ -109,6 +135,12 @@
|
||||
"authors": [ "mahmoudk1000" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "german2",
|
||||
"label": "German (GBoard)",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "greek",
|
||||
"label": "Ελληνικά",
|
||||
@@ -223,6 +255,13 @@
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian"
|
||||
},
|
||||
{
|
||||
"id": "persian2",
|
||||
"label": "Persian2",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian2"
|
||||
},
|
||||
{
|
||||
"id": "qwerty",
|
||||
"label": "QWERTY",
|
||||
@@ -346,6 +385,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "armenian",
|
||||
"label": "Armenian",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "arabic",
|
||||
"label": "Arabic",
|
||||
@@ -387,6 +432,12 @@
|
||||
"label": "Persian",
|
||||
"authors": [ "PHELAT" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "persian2",
|
||||
"label": "Persian2",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl"
|
||||
}
|
||||
],
|
||||
"extension": [
|
||||
@@ -540,6 +591,13 @@
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
{
|
||||
"id": "armenian",
|
||||
"label": "Armenian",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:armenian"
|
||||
},
|
||||
{
|
||||
"id": "cjk",
|
||||
"label": "CJK",
|
||||
@@ -592,6 +650,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "armenian",
|
||||
"label": "Armenian",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "cjk",
|
||||
"label": "CJK",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
{ "$": "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": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 105, "label": "i" },
|
||||
"upper": { "code": 304, "label": "İ" }
|
||||
},
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 287, "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" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 305, "label": "ı" },
|
||||
"upper": { "code": 73, "label": "I" }
|
||||
},
|
||||
{ "$": "auto_text_key", "code": 601, "label": "ə" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "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" },
|
||||
{ "$": "auto_text_key", "code": 231, "label": "ç" },
|
||||
{ "$": "auto_text_key", "code": 351, "label": "ş" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 59, "label": ";", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 58, "label": ":" }
|
||||
]
|
||||
} },
|
||||
"upper": { "code": 58, "label": ":", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 59, "label": ";" }
|
||||
]
|
||||
} }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,48 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1393, "label": "ձ" },
|
||||
{ "$": "auto_text_key", "code": 1397, "label": "յ" },
|
||||
{ "$": "auto_text_key", "code": 1413, "label": "օ" },
|
||||
{ "$": "auto_text_key", "code": 1404, "label": "ռ" },
|
||||
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
|
||||
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
|
||||
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
|
||||
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
|
||||
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
|
||||
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1389, "label": "խ" },
|
||||
{ "$": "auto_text_key", "code": 1410, "label": "ւ" },
|
||||
{ "$": "auto_text_key", "code": 1383, "label": "է" },
|
||||
{ "$": "auto_text_key", "code": 1408, "label": "ր" },
|
||||
{ "$": "auto_text_key", "code": 1407, "label": "տ" },
|
||||
{ "$": "auto_text_key", "code": 1381, "label": "ե" },
|
||||
{ "$": "auto_text_key", "code": 1384, "label": "ը" },
|
||||
{ "$": "auto_text_key", "code": 1387, "label": "ի" },
|
||||
{ "$": "auto_text_key", "code": 1400, "label": "ո" },
|
||||
{ "$": "auto_text_key", "code": 1402, "label": "պ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1377, "label": "ա" },
|
||||
{ "$": "auto_text_key", "code": 1405, "label": "ս" },
|
||||
{ "$": "auto_text_key", "code": 1380, "label": "դ" },
|
||||
{ "$": "auto_text_key", "code": 1414, "label": "ֆ" },
|
||||
{ "$": "auto_text_key", "code": 1412, "label": "ք" },
|
||||
{ "$": "auto_text_key", "code": 1392, "label": "հ" },
|
||||
{ "$": "auto_text_key", "code": 1395, "label": "ճ" },
|
||||
{ "$": "auto_text_key", "code": 1391, "label": "կ" },
|
||||
{ "$": "auto_text_key", "code": 1388, "label": "լ" },
|
||||
{ "$": "auto_text_key", "code": 1385, "label": "թ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1382, "label": "զ" },
|
||||
{ "$": "auto_text_key", "code": 1409, "label": "ց" },
|
||||
{ "$": "auto_text_key", "code": 1379, "label": "գ" },
|
||||
{ "$": "auto_text_key", "code": 1406, "label": "վ" },
|
||||
{ "$": "auto_text_key", "code": 1378, "label": "բ" },
|
||||
{ "$": "auto_text_key", "code": 1398, "label": "ն" },
|
||||
{ "$": "auto_text_key", "code": 1396, "label": "մ" },
|
||||
{ "$": "auto_text_key", "code": 1399, "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" }
|
||||
]
|
||||
]
|
||||
@@ -2,44 +2,85 @@
|
||||
[
|
||||
{ "code": 39, "label": "'", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1474, "label": "ש\u05c2" },
|
||||
{ "code": 1467, "label": "ס\u05bb" },
|
||||
{ "code": 1523, "label": "׳" },
|
||||
{ "code": 1524, "label": "״" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 96, "label": "`" }
|
||||
]
|
||||
} },
|
||||
{ "code": 45, "label": "-", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1470, "label": "־" },
|
||||
{ "code": 1473, "label": "ש\u05c1" },
|
||||
{ "code": 95, "label": "_" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1511, "label": "ק" },
|
||||
{ "code": 1511, "label": "ק", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1464, "label": "ס\u05b8" },
|
||||
{ "code": 1459, "label": "ס\u05b3" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1512, "label": "ר" },
|
||||
{ "code": 1488, "label": "א" },
|
||||
{ "code": 1496, "label": "ט" },
|
||||
{ "code": 1493, "label": "ו" },
|
||||
{ "code": 1493, "label": "ו", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1465, "label": "ס\u05b9" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1503, "label": "ן" },
|
||||
{ "code": 1501, "label": "ם" },
|
||||
{ "code": 1508, "label": "פ" }
|
||||
{ "code": 1508, "label": "פ", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1463, "label": "ס\u05b7" },
|
||||
{ "code": 1458, "label": "ס\u05b2" }
|
||||
]
|
||||
} }
|
||||
],
|
||||
[
|
||||
{ "code": 1513, "label": "ש" },
|
||||
{ "code": 1491, "label": "ד" },
|
||||
{ "code": 1513, "label": "ש", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1456, "label": "ס\u05b0" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1491, "label": "ד", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1468, "label": "ס\u05bc" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1490, "label": "ג" },
|
||||
{ "code": 1499, "label": "כ" },
|
||||
{ "code": 1506, "label": "ע" },
|
||||
{ "code": 1497, "label": "י" },
|
||||
{ "code": 1495, "label": "ח" },
|
||||
{ "code": 1495, "label": "ח", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1460, "label": "ס\u05b4" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1500, "label": "ל" },
|
||||
{ "code": 1498, "label": "ך" },
|
||||
{ "code": 1507, "label": "ף" }
|
||||
],
|
||||
[
|
||||
{ "code": 1494, "label": "ז" },
|
||||
{ "code": 1505, "label": "ס" },
|
||||
{ "code": 1505, "label": "ס", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1462, "label": "ס\u05b6" },
|
||||
{ "code": 1457, "label": "ס\u05b1" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1489, "label": "ב" },
|
||||
{ "code": 1492, "label": "ה" },
|
||||
{ "code": 1504, "label": "נ" },
|
||||
{ "code": 1502, "label": "מ" },
|
||||
{ "code": 1510, "label": "צ" },
|
||||
{ "code": 1510, "label": "צ", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1461, "label": "ס\u05b5" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1514, "label": "ת" },
|
||||
{ "code": 1509, "label": "ץ" }
|
||||
]
|
||||
|
||||
@@ -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,49 @@
|
||||
[
|
||||
[
|
||||
|
||||
{ "$": "auto_text_key", "code": 1393, "label": "ձ" },
|
||||
{ "$": "auto_text_key", "code": 1397, "label": "յ" },
|
||||
{ "$": "auto_text_key", "code": 1413, "label": "օ" },
|
||||
{ "$": "auto_text_key", "code": 1404, "label": "ռ" },
|
||||
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
|
||||
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
|
||||
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
|
||||
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
|
||||
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
|
||||
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1389, "label": "խ" },
|
||||
{ "$": "auto_text_key", "code": 1406, "label": "վ" },
|
||||
{ "$": "auto_text_key", "code": 1383, "label": "է" },
|
||||
{ "$": "auto_text_key", "code": 1408, "label": "ր" },
|
||||
{ "$": "auto_text_key", "code": 1380, "label": "դ" },
|
||||
{ "$": "auto_text_key", "code": 1381, "label": "ե" },
|
||||
{ "$": "auto_text_key", "code": 1384, "label": "ը" },
|
||||
{ "$": "auto_text_key", "code": 1387, "label": "ի" },
|
||||
{ "$": "auto_text_key", "code": 1400, "label": "ո" },
|
||||
{ "$": "auto_text_key", "code": 1378, "label": "բ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1377, "label": "ա" },
|
||||
{ "$": "auto_text_key", "code": 1405, "label": "ս" },
|
||||
{ "$": "auto_text_key", "code": 1407, "label": "տ" },
|
||||
{ "$": "auto_text_key", "code": 1414, "label": "ֆ" },
|
||||
{ "$": "auto_text_key", "code": 1391, "label": "կ" },
|
||||
{ "$": "auto_text_key", "code": 1392, "label": "հ" },
|
||||
{ "$": "auto_text_key", "code": 1395, "label": "ճ" },
|
||||
{ "$": "auto_text_key", "code": 1412, "label": "ք" },
|
||||
{ "$": "auto_text_key", "code": 1388, "label": "լ" },
|
||||
{ "$": "auto_text_key", "code": 1385, "label": "թ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1382, "label": "զ" },
|
||||
{ "$": "auto_text_key", "code": 1409, "label": "ց" },
|
||||
{ "$": "auto_text_key", "code": 1379, "label": "գ" },
|
||||
{ "$": "auto_text_key", "code": 1410, "label": "ւ" },
|
||||
{ "$": "auto_text_key", "code": 1402, "label": "պ" },
|
||||
{ "$": "auto_text_key", "code": 1398, "label": "ն" },
|
||||
{ "$": "auto_text_key", "code": 1396, "label": "մ" },
|
||||
{ "$": "auto_text_key", "code": 1399, "label": "շ" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
[
|
||||
[
|
||||
{ "code": -11, "label": "shift", "type": "modifier" },
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "$": "variation_selector",
|
||||
"default": { "code": 44, "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": 1417, "label": "։", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -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,92 @@
|
||||
[
|
||||
[
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 35, "label": "#", "popup": {
|
||||
"main": { "code": 8470, "label": "№" }
|
||||
} },
|
||||
{ "code": -801, "label": "currency_slot_1", "popup": {
|
||||
"main": { "code": -802, "label": "currency_slot_2" },
|
||||
"relevant": [
|
||||
{ "code": -806, "label": "currency_slot_6" },
|
||||
{ "code": -803, "label": "currency_slot_3" },
|
||||
{ "code": -804, "label": "currency_slot_4" },
|
||||
{ "code": -805, "label": "currency_slot_5" }
|
||||
]
|
||||
} },
|
||||
{ "code": 37, "label": "%", "popup": {
|
||||
"main": { "code": 8240, "label": "‰" },
|
||||
"relevant": [
|
||||
{ "code": 8453, "label": "℅" }
|
||||
]
|
||||
} },
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 45, "label": "-", "popup": {
|
||||
"main": { "code": 95, "label": "_" },
|
||||
"relevant": [
|
||||
{ "code": 8212, "label": "—" },
|
||||
{ "code": 8211, "label": "–" },
|
||||
{ "code": 183, "label": "·" }
|
||||
]
|
||||
} },
|
||||
{ "code": 43, "label": "+", "popup": {
|
||||
"main": { "code": 177, "label": "±" }
|
||||
} },
|
||||
{ "code": 40, "label": "(", "popup": {
|
||||
"main": { "code": 60, "label": "<" },
|
||||
"relevant": [
|
||||
{ "code": 91, "label": "[" },
|
||||
{ "code": 123, "label": "{" }
|
||||
]
|
||||
} },
|
||||
{ "code": 41, "label": ")", "popup": {
|
||||
"main": { "code": 62, "label": ">" },
|
||||
"relevant": [
|
||||
{ "code": 93, "label": "]" },
|
||||
{ "code": 125, "label": "}" }
|
||||
]
|
||||
} },
|
||||
{ "code": 47, "label": "/" }
|
||||
],
|
||||
[
|
||||
{ "code": 42, "label": "*", "popup": {
|
||||
"main": { "code": 8224, "label": "†" },
|
||||
"relevant": [
|
||||
{ "code": 9733, "label": "★" },
|
||||
{ "code": 8225, "label": "‡" }
|
||||
]
|
||||
} },
|
||||
{ "code": 171, "label": "«", "popup": {
|
||||
"main": { "code": 34, "label": "\"" },
|
||||
"relevant": [
|
||||
{ "code": 8221, "label": "”" },
|
||||
{ "code": 8222, "label": "„" },
|
||||
{ "code": 8220, "label": "“" },
|
||||
{ "code": 8249, "label": "‹" }
|
||||
]
|
||||
} },
|
||||
{ "code": 187, "label": "»", "popup": {
|
||||
"main": { "code": 39, "label": "'" },
|
||||
"relevant": [
|
||||
{ "code": 8217, "label": "’" },
|
||||
{ "code": 8218, "label": "‚" },
|
||||
{ "code": 8216, "label": "‘" },
|
||||
{ "code": 8250, "label": "›" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1373, "label": "՝", "popup": {
|
||||
"main": { "code": 58, "label": ":" }
|
||||
} },
|
||||
{ "code": 46, "label": "." },
|
||||
{ "code": 1372, "label": "՜", "popup": {
|
||||
"main": { "code": 33, "label": "!" }
|
||||
} },
|
||||
{ "code": 1374, "label": "՞", "popup": {
|
||||
"main": { "code": 63, "label": "?" },
|
||||
"relevant": [
|
||||
{ "code": 191, "label": "¿" },
|
||||
{ "code": 8253, "label": "‽" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1371, "label": "՛" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
[
|
||||
{ "code": -203, "label": "view_symbols2", "type": "system_gui" },
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -201, "label": "view_characters", "type": "system_gui" },
|
||||
{ "code": 44, "label": "," },
|
||||
{ "code": -205, "label": "view_numeric_advanced", "type": "system_gui" },
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 1417, "label": "։", "popup": {
|
||||
"main": { "code": 46, "label": "." }
|
||||
} },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -70,6 +70,10 @@
|
||||
"id": "fa",
|
||||
"authors": [ "PHELAT" ]
|
||||
},
|
||||
{
|
||||
"id": "fa2",
|
||||
"authors": [ "M-Koushan" ]
|
||||
},
|
||||
{
|
||||
"id": "fi",
|
||||
"authors": [ "patrickgold" ]
|
||||
@@ -90,6 +94,10 @@
|
||||
"id": "hu",
|
||||
"authors": [ "zoli111, gabik65" ]
|
||||
},
|
||||
{
|
||||
"id": "hy",
|
||||
"authors": [ "PJTSearch" ]
|
||||
},
|
||||
{
|
||||
"id": "is",
|
||||
"authors": [ "patrickgold" ]
|
||||
@@ -172,7 +180,11 @@
|
||||
},
|
||||
{
|
||||
"id": "uk",
|
||||
"authors": [ "williamtheaker", "33kk" ]
|
||||
"authors": [ "williamtheaker", "33kk", "honsiorovskyi" ]
|
||||
},
|
||||
{
|
||||
"id": "uk-cyr-ext",
|
||||
"authors": [ "williamtheaker", "33kk", "honsiorovskyi" ]
|
||||
},
|
||||
{
|
||||
"id": "ur-PK",
|
||||
@@ -423,6 +435,18 @@
|
||||
"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": "ar",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -435,6 +459,15 @@
|
||||
"numericRow": "org.florisboard.layouts:eastern_arabic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "az",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:azerbaijani_manat",
|
||||
"popupMapping": "org.florisboard.localization:tr",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:azerbaijani"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "hu",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -462,6 +495,26 @@
|
||||
"characters": "org.florisboard.layouts:qwertz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "hy",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:armenian_dram",
|
||||
"popupMapping": "org.florisboard.localization:hy",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:western_armenian",
|
||||
"symbols": "org.florisboard.layouts:armenian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "hy",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:armenian_dram",
|
||||
"popupMapping": "org.florisboard.localization:hy",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:eastern_armenian",
|
||||
"symbols": "org.florisboard.layouts:armenian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ru",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"main": { "code": -255, "label": ".sa"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
|
||||
@@ -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": "!" }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
]
|
||||
},
|
||||
"ا": {
|
||||
"main": { "code": 1570, "label": "آ"},
|
||||
"relevant": [
|
||||
{ "code": 1649, "label": "ٱ" },
|
||||
{ "code": 1569, "label": "ء" },
|
||||
{ "code": 1571, "label": "أ" },
|
||||
{ "code": 1573, "label": "إ" },
|
||||
{ "code": 1570, "label": "آ" }
|
||||
{ "code": 1573, "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,41 @@
|
||||
{
|
||||
"all": {
|
||||
"ե": {
|
||||
"main": { "$": "auto_text_key", "code": 1415, "label": "և" }
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 171, "label": "«" },
|
||||
{ "code": 187, "label": "»" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 1373, "label": "՝" },
|
||||
{ "code": 1371, "label": "՛" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 46, "label": "." },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "code": 40, "label": "(" },
|
||||
{ "code": 41, "label": ")" },
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 1372, "label": "՜" },
|
||||
{ "code": 1374, "label": "՞" },
|
||||
{ "code": 1415, "label": "և" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".gr" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "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" }
|
||||
]
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"main": { "code": -255, "label": ".pk"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
|
||||
@@ -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)",
|
||||
@@ -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}][mode={m:capslock}]": {
|
||||
"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)",
|
||||
@@ -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}][mode={m:capslock}]": {
|
||||
"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}][mode={m:capslock}]": {
|
||||
"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}][mode={m:capslock}]": {
|
||||
"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,36 +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.common
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
class RegexSerializer : KSerializer<Regex> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ThemeValue", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Regex) {
|
||||
encoder.encodeString(value.toString())
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Regex {
|
||||
return decoder.decodeString().toRegex()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -22,28 +22,28 @@ 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.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 +67,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) }
|
||||
@@ -89,7 +90,7 @@ class FlorisApplication : Application() {
|
||||
)
|
||||
CrashUtility.install(this)
|
||||
|
||||
if (AndroidVersion.ATLEAST_API24_N && !UserManagerCompat.isUserUnlocked(this)) {
|
||||
if (!UserManagerCompat.isUserUnlocked(this)) {
|
||||
val context = createDeviceProtectedStorageContext()
|
||||
initICU(context)
|
||||
prefs.initializeBlocking(context)
|
||||
@@ -162,6 +163,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.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,23 +218,28 @@ 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 {
|
||||
setTheme(R.style.FlorisImeTheme)
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -226,7 +248,7 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
}
|
||||
|
||||
override fun onCreateInputView(): View {
|
||||
super.onCreateInputView()
|
||||
super.installViewTreeOwners()
|
||||
val composeView = ComposeInputView()
|
||||
inputWindowView = composeView
|
||||
return composeView
|
||||
@@ -237,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()
|
||||
}
|
||||
}
|
||||
@@ -273,50 +310,45 @@ 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 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()
|
||||
@@ -341,14 +373,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)
|
||||
@@ -420,7 +472,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
|
||||
@@ -432,15 +484,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()
|
||||
@@ -452,7 +528,7 @@ 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,
|
||||
@@ -467,7 +543,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 },
|
||||
@@ -521,23 +596,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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,4 +626,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,45 @@ 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 activeEditorInfo by editorInstance.activeInfoFlow.collectAsState()
|
||||
val activeEditorContent by editorInstance.activeContentFlow.collectAsState()
|
||||
val selection = activeEditorContent.selection
|
||||
|
||||
DevtoolsOverlayBox(title = "Input state overlay") {
|
||||
DevtoolsSubGroup(title = "EditorInfo") {
|
||||
DevtoolsText(text = "Type=${activeEditorInfo.inputAttributes.type} Variation=${activeEditorInfo.inputAttributes.variation} IsRich=${activeEditorInfo.isRichInputEditor}")
|
||||
DevtoolsText(text = "Selection { start=${selection.start}, end=${selection.end} }")
|
||||
}
|
||||
DevtoolsSubGroup(title = "EditorContent") {
|
||||
DevtoolsText(text = "Before: \"${activeEditorContent.textBeforeSelection}\"")
|
||||
DevtoolsText(text = "Selected: \"${activeEditorContent.selectedText}\"")
|
||||
DevtoolsText(text = "After: \"${activeEditorContent.textAfterSelection}\"")
|
||||
DevtoolsText(text = "ComposingWord: ${activeEditorContent.composing}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsSpellingOverlay() {
|
||||
val context = LocalContext.current
|
||||
@@ -87,18 +125,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 +159,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.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
|
||||
@@ -267,17 +266,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
|
||||