Compare commits

...

45 Commits

Author SHA1 Message Date
Patrick Goldinger
ac162a8a91 Temp 2024-07-08 19:51:47 +02:00
klaurence
be4cd4d897 Change files of Udmurt subtype (#2445)
* Update extension.json

* Update udmurt_compact.json

* Update udmurt_compact.json
2024-07-08 03:48:22 +02:00
JP O'Neill
e46d53291b add support for the layout colemak-dhm (#2357)
Co-authored-by: JP O'Neill <oneilljp@proton.me>
2024-07-08 03:37:36 +02:00
Victor B
8292f9d4cc Add ЈЦУКЕН interslavic keyboard layout (#2354) 2024-07-08 03:37:07 +02:00
Thanh, H
192412b6dd Improve Vietnamese Telex keyboard (#2259)
* Init Full Telex

* Add Telex Rule for a__

* Add a__, ă__, â__ rule

* Update ô, ơ, ư, iê without sound

* Add ơ, iê, uyê. yê without sound

* Add ăc, ăm

* Add êm

* Add ăn

* Update ô

* Improve Vietnamese

* Add "ưc"

* Special case: "gi" + vowel + tone

* Special case: "ghi" + tone + "ê"

* Special case: "gi" + "a, u" + "tone"

* Add change tone feature: "áf" -> "à"

* Add tone remove for iê case
2024-07-08 03:23:14 +02:00
GasparAM
a7f8980d35 Added Armenian alternative phonetic layout (#2171) 2024-07-08 03:18:55 +02:00
moonbeamcelery
f5d80a5818 CJK keyboard adjustments for better Chinese input convenience (#2142)
* CJK keyboard fixes, see expanded message:

- fix full-width comma
- add () to first symbol screen popups
- merge postal sign with # popups
- add = to + popup
- add full-width = to half-width popup
- fix half-width <> and single guillemets ‹›
- add check mark to square root symbol popup
- Add [] to popups
- Add pinyin characters in popup mapping

Signed-off-by: moonbeamcelery <moonbeamcelery@proton.me>

* fix: issue with brackets, ü, and add cjk popup to Chinese preset

---------

Signed-off-by: moonbeamcelery <moonbeamcelery@proton.me>
2024-07-08 03:16:36 +02:00
Patrick Goldinger
d9b940f4f3 Add possible detection for "All keys invisible" bug (#2501) 2024-07-08 02:38:21 +02:00
Lars Mühlbauer
d86fc13cff Remove material2 dependency (#2500)
* remove material2

* fix icon rotation in smartbar

* add FB icon for Android Studio's NewUI

* Add new button styling option for clipboard history view
replace one hand mode icon

* apply review suggestions

* ah yes, the trailing commas
2024-07-08 01:54:29 +02:00
Patrick Goldinger
5b7727b884 Merge pull request #2499 from florisboard/refactor/move-lib-snygg
Move `lib.snygg` to separate module
2024-07-05 20:49:19 +02:00
Patrick Goldinger
b0649b1b7e Move lib.snygg to separate module 2024-07-05 19:43:00 +02:00
Patrick Goldinger
6244198795 Rework enum display string strategy
Preparation for further lib de-entanglement
2024-07-05 17:56:29 +02:00
Patrick Goldinger
bd9f7750aa Move lib.android to separate module (#2498) 2024-07-05 15:59:37 +02:00
Patrick Goldinger
c909d3ad7d Merge pull request #2473 from florisboard/feat/addons-support
Add addons support
2024-07-04 19:31:11 +02:00
lm41
736411e4f3 change hardcoded uri build config uri 2024-07-04 19:21:18 +02:00
lm41
9c7d980b3b localize addon manager 2024-07-04 18:47:09 +02:00
lm41
4d04eb1bb5 update ROADMAP.md 2024-06-30 17:54:11 +02:00
lm41
68c55d66be add better one hand mode icon 2024-06-28 12:40:16 +02:00
lm41
e1550d813b Remove AssetManager and switch to extension functions 2024-06-26 20:45:01 +02:00
lm41
f780ef0213 localize ExtensionValidation 2024-06-24 21:35:15 +02:00
lm41
025620a262 add FLADDONS_*** prefix to BuildConfig fields 2024-06-23 21:41:04 +02:00
lm41
4b83c907c3 simplify code 2024-06-23 19:43:51 +02:00
lm41
5542a131b9 Update UX for managing Extensions 2024-06-23 14:03:17 +02:00
kuroya
eb50498890 Add Diktor layout (#2495)
* Add Diktor layout

* change tab to spaces
2024-06-22 13:58:48 +02:00
Lars Mühlbauer
e6a408fbc0 Remove deprecated swipe-able API and switch to M3 ModalBottomSheet (#2496) 2024-06-22 13:50:14 +02:00
Lars Mühlbauer
9d76b684be Fix suggestion engine selection crash (#2492)
* fix suggestion engine selection crash

* replace rtl modifier with auto mirrored icon

* remove unnecessary OptIn annotation
2024-06-22 13:38:06 +02:00
lm41
b97cc52958 fix url encoding 2024-06-13 19:35:01 +02:00
lm41
aac7134433 add funktion to create an extension update url 2024-06-05 16:31:40 +02:00
Patrick Goldinger
f1d60d9958 Add barebones implementation for addons screen 2024-06-03 15:55:59 +02:00
lm41
e520a9c335 Prevent file/path name max length attacks 2024-06-02 13:55:39 +02:00
lm41
30294b02b4 Prevent large file size attacks by limiting the max file size to 100MB 2024-06-02 00:58:44 +02:00
Patrick Goldinger
f1bdf216fc Add error condition for failing octet-streams 2024-06-02 00:19:28 +02:00
lm41
82d43a53cc prevent zip-slip when unpacking an extension 2024-06-01 21:42:56 +02:00
Patrick Goldinger
c51a787ac4 Fix import extension intents for Firefox 2024-06-01 21:11:23 +02:00
Lars Mühlbauer
f116e20829 Remove systemuicontroller and switch to view apis (#2486) 2024-06-01 12:27:06 +02:00
lm41
baf2cbcd13 Add share import handler for .flex files 2024-05-31 18:01:03 +02:00
lm41
1edb90b0f7 change flex file importer mimetype to application/vnd.florisboard.extension+zip 2024-05-31 14:31:19 +02:00
Lars Mühlbauer
4c0c3f52e7 Smartbar enhancements (#2477)
* fix incorrect smartbar paste button state

* Add incognito mode indicator in Smartbar

* apply suggestions
2024-05-29 22:49:38 +02:00
Md. Rifat Hasan Jihan
d23575375d Updated bn-BD layout with the latest Unijoy layout (#2417)
and refined the popup keys
2024-05-29 07:51:09 +02:00
Lars Mühlbauer
e95bbf5192 Fix fullscreen input mode in portrait orientation (#2475) 2024-05-29 07:42:07 +02:00
Patrick Goldinger
0a4a4418ca Revamp theme settings screen 2024-05-13 01:53:28 +02:00
Patrick Goldinger
2c653853e2 Add basic support for importing flex files from the file explorer 2024-05-13 00:30:18 +02:00
Lars Mühlbauer
6f169997e9 Migrate Settings UI to Material 3 (#2467)
* implement material3 for the settings ui

* fix chip colors

* fix statusbar color

* fix aboutlibraries color

* fix alignment of subcheckboxen

* fix wrong card colors

* Update cornershape of the dropdown menu

* update ScrollableModifiers to material 3

* better card and background colors

* update jetpref

* change contrast of outlined cards

* apply suggestions

* implement suggestions

* add corners on text background in the theme editor

* apply the systembar color for the navbar

* set material you as default on android 12+

* fix card content padding

* Fix status bar color not adapting to navbar color state

* update jetpref dependency to 0.2.0-beta01

---------

Co-authored-by: Patrick Goldinger <patrick@patrickgold.dev>
2024-05-08 00:29:42 +02:00
Patrick Goldinger
f2e76cc72a Fix emoji suggestion logic (#2462)
* Rework emoji suggestion (#2460)

* Apply suggestions from code review

* Fix emoji suggestions caring about capitalization
2024-05-03 20:37:06 +02:00
Lars Mühlbauer
3da59cc94b Add clipboard history to backup (#2458)
* Implement backup/restore clipboard history

* Fix duplicate clipboard items when merging the same archive multiple times

* Apply suggestions

* Update UI

* Implement backup of media clipboard history items.

* Implement restore and add strings; apply suggestions

* change from popBackStack() to navigateUp()
2024-04-29 21:14:06 +02:00
239 changed files with 4709 additions and 2960 deletions

226
.idea/icon.svg generated Normal file
View File

@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="vector"
width="108"
height="108"
viewBox="0 0 108 108"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10">
<radialGradient
gradientUnits="userSpaceOnUse"
r="20.594"
cx="54.141998"
cy="48.769001"
id="gradient_0"
gradientTransform="matrix(2.193116,0,0,2.193116,-64.427669,-59.442216)">
<stop
offset="0"
stop-color="#55E032FF"
id="stop1" />
<stop
offset="1"
stop-color="#227C53FF"
id="stop2" />
</radialGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
r="20.594"
cx="54.141998"
cy="48.769001"
id="gradient_1"
gradientTransform="matrix(2.193116,0,0,2.193116,-64.427669,-59.442216)">
<stop
offset="0"
stop-color="#55E032FF"
id="stop3" />
<stop
offset="1"
stop-color="#227C53FF"
id="stop4" />
</radialGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
r="12.849"
cx="54.029999"
cy="39.144001"
id="gradient_2"
gradientTransform="matrix(2.193116,0,0,2.193116,-64.427669,-59.442216)">
<stop
offset="0"
stop-color="#FE7901FF"
id="stop5" />
<stop
offset="1"
stop-color="#FEBE01FF"
id="stop6" />
</radialGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
r="20.594"
cx="54.141998"
cy="48.769001"
id="gradient_3"
gradientTransform="matrix(2.193116,0,0,2.193116,-64.427669,-59.442216)">
<stop
offset="0"
stop-color="#55E032FF"
id="stop7" />
<stop
offset="1"
stop-color="#227C53FF"
id="stop8" />
</radialGradient>
<radialGradient
gradientUnits="userSpaceOnUse"
r="17.913"
cx="54.131001"
cy="49.819"
id="gradient_4"
gradientTransform="matrix(2.193116,0,0,2.193116,-64.427669,-59.442216)">
<stop
offset="0"
stop-color="#FE7901FF"
id="stop9" />
<stop
offset="1"
stop-color="#FEBE01FF"
id="stop10" />
</radialGradient>
</defs>
<path
fill="url(#gradient_0)"
d="m 12.291915,34.438502 0.434238,0.0066 c 20.014377,0.256595 36.184221,16.58873 36.184221,36.666707 v 6.504782 C 46.434346,77.090222 43.999987,76.362108 41.642388,75.436613 27.045007,69.710386 16.044337,56.538532 13.081437,41.131892 12.655973,38.923423 12.392799,36.686445 12.289722,34.440694 Z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_0"
style="fill:url(#gradient_0);stroke-width:2.19311" />
<path
fill="url(#gradient_1)"
d="m 41.438428,33.83978 c 1.451843,-7.875479 5.219616,-15.404446 11.305513,-21.490344 0.497838,-0.497837 1.004447,-0.980322 1.524216,-1.449649 0.517575,0.469327 1.026378,0.951812 1.526409,1.449649 6.074931,6.077125 9.842705,13.595127 11.29674,21.459641 -5.296375,4.153762 -9.689186,9.412854 -12.829729,15.428571 -3.136156,-5.974047 -7.53774,-11.23314 -12.823149,-15.395674 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_1"
style="fill:url(#gradient_1);stroke-width:2.19311" />
<path
fill="url(#gradient_2)"
d="M 33.758135,28.900884 C 35.892037,20.613098 40.199317,12.774901 46.684361,6.2876637 48.478331,4.4936948 50.377569,2.8642095 52.362338,1.4035943 L 54.268157,0 56.176168,1.4035943 c 1.984769,1.4628084 3.884009,3.0901005 5.677977,4.8840694 6.480658,6.4806583 10.790132,14.3210483 12.924033,22.6022543 -2.015473,1.030764 -3.949802,2.199695 -5.783247,3.49802 C 67.332549,24.486141 63.437574,16.961559 57.307815,10.833993 56.548998,10.072982 55.768249,9.3492537 54.965567,8.6584222 L 54.265964,8.0553153 53.56636,8.6584222 C 52.765872,9.3492537 51.985123,10.072982 51.226304,10.833993 45.089966,16.970332 41.190606,24.503686 39.53261,32.414255 37.694779,31.111545 35.764837,29.933841 33.753749,28.900884 Z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_2"
style="fill:url(#gradient_2);stroke-width:2.19311" />
<path
fill="url(#gradient_3)"
d="m 96.244398,34.438502 -0.434237,0.0066 c -20.01657,0.256595 -36.186415,16.58873 -36.186415,36.666707 v 6.506976 C 79.890332,73.322449 95.279427,55.74901 96.244398,34.440694 Z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_3"
style="fill:url(#gradient_3);stroke-width:2.19311" />
<path
fill="url(#gradient_4)"
d="m 12.68887,25.874383 0.149132,0.0022 c 4.506853,0.05702 8.996162,0.787328 13.290282,2.168991 11.959063,3.851112 21.891685,12.759549 27.168322,24.058483 l 0.973744,2.083461 0.969357,-2.085654 C 62.347596,36.789522 77.776168,26.104661 95.702698,25.876577 l 0.149133,-0.0022 c 0.291684,2.098811 0.443009,4.241486 0.445201,6.421443 l -0.510995,0.0066 C 74.600536,32.576546 57.485458,49.860493 57.485458,71.111788 v 6.917088 c -1.048309,0.155711 -2.046178,0.188608 -3.079135,0.192995 h -0.13378 c -1.068047,0 -2.144867,-0.07238 -3.212915,-0.219313 v -6.89077 c 0,-21.251295 -17.117271,-38.535242 -38.300578,-38.809382 l -0.510997,-0.0066 c 0,-2.147061 0.149133,-4.296315 0.445203,-6.421443 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_4"
style="fill:url(#gradient_4);stroke-width:2.19311" />
<path
fill="#53cd53"
d="m 101.9772,99.716601 c 0,-2.46287 -1.997925,-4.462992 -4.460795,-4.462992 H 85.243728 c -2.460676,0 -4.460798,1.997929 -4.460798,4.462992 v 3.822599 c 0,2.46068 1.997928,4.4608 4.460798,4.4608 h 12.272677 c 2.460676,0 4.460795,-1.99793 4.460795,-4.4608 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_5"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 78.620517,84.818763 c 0,-2.460676 -1.997928,-4.460798 -4.460797,-4.460798 h -6.096864 c -2.460676,0 -4.460798,1.997929 -4.460798,4.460798 v 3.824795 c 0,2.460676 1.997929,4.460798 4.460798,4.460798 h 6.096864 c 2.460676,0 4.460797,-1.997929 4.460797,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_6"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 61.450612,84.818763 c 0,-2.460676 -1.997929,-4.460798 -4.460798,-4.460798 h -6.09467 c -2.460676,0 -4.460798,1.997929 -4.460798,4.460798 v 3.824795 c 0,2.460676 1.997929,4.460798 4.460798,4.460798 h 6.09467 c 2.460676,0 4.460798,-1.997929 4.460798,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_7"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 27.11738,84.818763 c 0,-2.460676 -1.997929,-4.460798 -4.460798,-4.460798 h -6.096863 c -2.460676,0 -4.460798,1.997929 -4.460798,4.460798 v 3.824795 c 0,2.460676 1.997929,4.460798 4.460798,4.460798 h 6.096863 c 2.460676,0 4.460798,-1.997929 4.460798,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_8"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 95.78823,84.818763 c 0,-2.460676 -1.997929,-4.460798 -4.460798,-4.460798 h -6.09467 c -2.462869,0 -4.462991,1.997929 -4.462991,4.460798 v 3.824795 c 0,2.460676 1.997928,4.460798 4.462991,4.460798 h 6.09467 c 2.460676,0 4.460798,-1.997929 4.460798,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_9"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 21.038062,69.923119 c 0,-2.46287 -1.997928,-4.462991 -4.460797,-4.462991 h -6.09467 c -2.4606765,0 -4.4607984,1.997929 -4.4607984,4.462991 v 3.822601 c 0,2.460676 1.9979288,4.460798 4.4607984,4.460798 h 6.09467 c 2.460676,0 4.460797,-1.997928 4.460797,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_10"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 101.9772,69.923119 c 0,-2.46287 -1.997925,-4.462991 -4.460795,-4.462991 h -6.09467 c -2.460676,0 -4.460797,1.997929 -4.460797,4.462991 v 3.822601 c 0,2.460676 1.997928,4.460798 4.460797,4.460798 h 6.09467 c 2.460676,0 4.460795,-1.997928 4.460795,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_11"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 44.282899,84.818763 c 0,-2.460676 -1.997928,-4.460798 -4.460798,-4.460798 h -6.09467 c -2.462869,0 -4.462991,1.997929 -4.462991,4.460798 v 3.824795 c 0,2.460676 1.99793,4.460798 4.462991,4.460798 h 6.09467 c 2.460676,0 4.460798,-1.997929 4.460798,-4.460798 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_12"
style="stroke-width:2.19311" />
<path
fill="#fe9801"
d="m 27.21607,99.716601 c 0,-2.46287 -1.997928,-4.462992 -4.460798,-4.462992 H 10.482595 c -2.4606765,0 -4.4607984,1.997929 -4.4607984,4.462992 v 3.822599 c 0,2.46068 1.9979288,4.4608 4.4607984,4.4608 h 12.272677 c 2.460676,0 4.460798,-1.99793 4.460798,-4.4608 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_13"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 83.756795,67.041365 c 0.655742,0.776363 1.054889,1.783003 1.054889,2.881754 v 3.822601 c 0,2.460676 -1.997928,4.460798 -4.460798,4.460798 h -6.096863 c -1.557112,0 -2.927809,-0.798293 -3.723911,-2.006701 4.91258,-2.307158 9.377765,-5.414803 13.226683,-9.158452 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_14"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 24.529503,66.738714 c 3.796284,3.76558 8.20664,6.919282 13.066585,9.263722 -0.774169,1.320257 -2.210661,2.204082 -3.848919,2.204082 h -6.096862 c -2.460676,0 -4.460798,-1.997928 -4.460798,-4.460798 v -3.822601 c 0,-1.247883 0.510996,-2.375144 1.337801,-3.186598 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_15"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 14.015705,51.362778 c 1.868535,4.322632 4.359915,8.346999 7.366677,11.950289 h -4.822663 c -2.460676,0 -4.460798,-1.997928 -4.460798,-4.460797 v -3.824795 c 0,-1.517637 0.758819,-2.85763 1.916784,-3.664697 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_16"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 94.369284,51.764118 c 0.87286,0.813646 1.418946,1.975997 1.418946,3.263357 v 3.824795 c 0,2.460676 -1.997929,4.460797 -4.460798,4.460797 h -4.116479 c 2.897106,-3.471703 5.313921,-7.355711 7.156137,-11.548949 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_17"
style="stroke-width:2.19311" />
<path
fill="#ffffff"
d="m 78.782808,99.819677 c 0,-2.432165 -1.971611,-4.40597 -4.403777,-4.40597 H 33.738397 c -2.432166,0 -4.405969,1.973805 -4.405969,4.40597 v 3.774353 c 0,2.43217 1.973803,4.40378 4.405969,4.40378 h 40.640634 c 2.432166,0 4.403777,-1.97161 4.403777,-4.40378 z"
stroke-linejoin="round"
fill-rule="evenodd"
id="path_18"
style="stroke-width:2.19311" />
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -16,6 +16,8 @@ This includes, but is not exclusive to:
- Remove existing glide/swipe typing (see 0.5 milestone)
- Improvements in clipboard / emoji functionality (v0.4.0-beta01/beta02)
- Prepare project to have native code implemented in [Rust](https://www.rust-lang.org/) (v0.4.0-beta02)
- - Upgrade Settings UI to Material 3 (v0.4.0-beta03)
- Add support for importing extensions via system file handler APIs (relevant for Addons store) (v0.4.0-beta03)
Note that the previous versioning scheme has been dropped in favor of using a major.minor.patch versioning scheme, so versions like `0.3.16` are a thing of the past :)
@@ -32,7 +34,6 @@ Note that the previous versioning scheme has been dropped in favor of using a ma
- RFC document with technical details will be released later
- Add Tablet mode / Optimizations for landscape input based on new keyboard layout engine
- Reimplementation of glide typing with the new layout engine and predictive text core
- Add support for importing extensions via system file handler APIs (relevant for Addons store)
- Add support for any remaining new features introduced with Android 13
## 0.6
@@ -52,7 +53,6 @@ Note that the previous versioning scheme has been dropped in favor of using a ma
**Features that MAY be added (even in versions mentioned above) or dismissed**
- Upgrade Settings UI to Material 3
- Full on-board layout editor which allows users to create their own layouts without writing a JSON file
- Theme rework part II
- Adaptive themes v2

View File

@@ -64,6 +64,8 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
buildConfigField("String", "BUILD_COMMIT_HASH", "\"${getGitCommitHash()}\"")
buildConfigField("String", "FLADDONS_API_VERSION", "\"v~draft2\"")
buildConfigField("String", "FLADDONS_STORE_URL", "\"fladdonstest.patrickgold.dev\"")
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
@@ -174,12 +176,10 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach
}
dependencies {
implementation(libs.accompanist.systemuicontroller)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.activity.ktx)
implementation(libs.androidx.autofill)
implementation(libs.androidx.collection.ktx)
implementation(libs.androidx.compose.material)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.runtime.livedata)
implementation(libs.androidx.compose.ui)
@@ -204,8 +204,10 @@ dependencies {
implementation(libs.patrickgold.jetpref.datastore.ui)
implementation(libs.patrickgold.jetpref.material.ui)
implementation(project(":lib:android"))
implementation(project(":lib:kotlin"))
implementation(project(":lib:native"))
implementation(project(":lib:snygg"))
testImplementation(libs.equalsverifier)
testImplementation(libs.kotest.assertions.core)

View File

@@ -84,10 +84,23 @@
android:roundIcon="@mipmap/floris_app_icon_round"
android:windowSoftInputMode="adjustResize"
android:theme="@style/FlorisAppTheme.Splash"
android:exported="false">
android:exported="true">
<intent-filter>
<data android:scheme="florisboard" android:host="app-ui"/>
</intent-filter>
<intent-filter android:label="Import Extension">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="content"/>
<data android:mimeType="application/vnd.florisboard.extension+zip"/>
<data android:mimeType="application/octet-stream"/><!-- Firefox looking at you :eyes: -->
</intent-filter>
<intent-filter android:label="Import Extension">
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.florisboard.extension+zip"/>
<data android:mimeType="application/octet-stream"/><!-- Firefox looking at you :eyes: -->
</intent-filter>
</activity>
<!-- Using an activity alias to disable/enable the app icon in the launcher -->
@@ -106,24 +119,6 @@
</intent-filter>
</activity-alias>
<!-- Import File Bridging Activity -->
<activity
android:name="dev.patrickgold.florisboard.app.ext.ImportFileActivity"
android:icon="@mipmap/floris_app_icon"
android:label="@string/settings__title"
android:launchMode="singleTask"
android:roundIcon="@mipmap/floris_app_icon_round"
android:windowSoftInputMode="adjustResize"
android:theme="@style/FlorisAppTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="*" android:host="*" android:pathPattern=".*\\.flex"/>
<data android:scheme="*" android:host="*" android:pathPattern=".*\\.xpi"/>
</intent-filter>
</activity>
<!-- Crash Dialog Activity -->
<activity
android:name="dev.patrickgold.florisboard.lib.crashutility.CrashDialogActivity"

View File

@@ -57,12 +57,89 @@
"ừz": "ư", "ửz": "ư", "ữz": "ư", "ứz": "ư", "ựz": "ư",
"ỳz": "y", "ỷz": "y", "ỹz": "y", "ýz": "y", "ỵz": "y",
"áf": "à", "ár": "ả", "áx": "ã", "áj": "ạ",
"às": "á", "àr": "ả", "àx": "ã", "àj": "ạ",
"ảs": "á", "ảf": "à", "ảx": "ã", "ảj": "ạ",
"ãs": "á", "ãf": "à", "ãr": "ả", "ãj": "ạ",
"ạs": "á", "ạf": "à", "ạr": "ả", "ạx": "ã",
"ấf": "ầ", "ấr": "ẩ", "ấx": "ẫ", "ấj": "ậ",
"ầs": "ấ", "ầr": "ẩ", "ầx": "ẫ", "ầj": "ậ",
"ẩs": "ấ", "ẩf": "ầ", "ẩx": "ẫ", "ẩj": "ậ",
"ẫs": "ấ", "ẫf": "ầ", "ẫr": "ẩ", "ẫj": "ậ",
"ậs": "ấ", "ậf": "ầ", "ậr": "ẩ", "ậx": "ẫ",
"ắf": "ằ", "ắr": "ẳ", "ắx": "ẵ", "ắj": "ặ",
"ằs": "ắ", "ằr": "ẳ", "ằx": "ẵ", "ằj": "ặ",
"ẳs": "ắ", "ẳf": "ằ", "ẳx": "ẵ", "ẳj": "ặ",
"ẵs": "ắ", "ẵf": "ằ", "ẵr": "ẳ", "ẵj": "ặ",
"ặs": "ắ", "ặf": "ằ", "ặr": "ẳ", "ặx": "ẵ",
"éf": "è", "ér": "ẻ", "éx": "ẽ", "éj": "ẹ",
"ès": "é", "èr": "ẻ", "èx": "ẽ", "èj": "ẹ",
"ẻs": "é", "ẻf": "è", "ẻx": "ẽ", "ẻj": "ẹ",
"ẽs": "é", "ẽf": "è", "ẽr": "ẻ", "ẽj": "ẹ",
"ẹs": "é", "ẹf": "è", "ẹr": "ẻ", "ẹx": "ẽ",
"ếf": "ề", "ếr": "ể", "ếx": "ễ", "ếj": "ệ",
"ềs": "ế", "ềr": "ể", "ềx": "ễ", "ềj": "ệ",
"ểs": "ế", "ểf": "ề", "ểx": "ễ", "ểj": "ệ",
"ễs": "ế", "ễf": "ề", "ễr": "ể", "ễj": "ệ",
"ệs": "ế", "ệf": "ề", "ệr": "ể", "ệx": "ễ",
"íf": "ì", "ír": "ỉ", "íx": "ĩ", "íj": "ị",
"ìs": "í", "ìr": "ỉ", "ìx": "ĩ", "ìj": "ị",
"ỉs": "í", "ỉf": "ì", "ỉx": "ĩ", "ỉj": "ị",
"ĩs": "í", "ĩf": "ì", "ĩr": "ỉ", "ĩj": "ị",
"ịs": "í", "ịf": "ì", "ịr": "ỉ", "ịx": "ĩ",
"óf": "ò", "ór": "ỏ", "óx": "õ", "ój": "ọ",
"òs": "ó", "òr": "ỏ", "òx": "õ", "òj": "ọ",
"ỏs": "ó", "ỏf": "ò", "ỏx": "õ", "ỏj": "ọ",
"õs": "ó", "õf": "ò", "õr": "ỏ", "õj": "ọ",
"ọs": "ó", "ọf": "ò", "ọr": "ỏ", "ọx": "õ",
"ốf": "ồ", "ốr": "ổ", "ốx": "ỗ", "ốj": "ộ",
"ồs": "ố", "ồr": "ổ", "ồx": "ỗ", "ồj": "ộ",
"ổs": "ố", "ổf": "ồ", "ổx": "ỗ", "ổj": "ộ",
"ỗs": "ố", "ỗf": "ồ", "ỗr": "ổ", "ỗj": "ộ",
"ộs": "ố", "ộf": "ồ", "ộr": "ổ", "ộx": "ỗ",
"ớf": "ờ", "ớr": "ở", "ớx": "ỡ", "ớj": "ợ",
"ờs": "ớ", "ờr": "ở", "ờx": "ỡ", "ờj": "ợ",
"ởs": "ớ", "ởf": "ờ", "ởx": "ỡ", "ởj": "ợ",
"ỡs": "ớ", "ỡf": "ờ", "ỡr": "ở", "ỡj": "ợ",
"ợs": "ớ", "ợf": "ờ", "ợr": "ở", "ợx": "ỡ",
"úf": "ù", "úr": "ủ", "úx": "ũ", "új": "ụ",
"ùs": "ú", "ùr": "ủ", "ùx": "ũ", "ùj": "ụ",
"ủs": "ú", "ủf": "ù", "ủx": "ũ", "ủj": "ụ",
"ũs": "ú", "ũf": "ù", "ũr": "ủ", "ũj": "ụ",
"ụs": "ú", "ụf": "ù", "ụr": "ủ", "ụx": "ũ",
"ứf": "ừ", "ứr": "ử", "ứx": "ữ", "ứj": "ự",
"ừs": "ứ", "ừr": "ử", "ừx": "ữ", "ừj": "ự",
"ửs": "ứ", "ửf": "ừ", "ửx": "ữ", "ửj": "ự",
"ữs": "ứ", "ữf": "ừ", "ữr": "ử", "ữj": "ự",
"ựs": "ứ", "ựf": "ừ", "ựr": "ử", "ựx": "ữ",
"ýf": "ỳ", "ýr": "ỷ", "ýx": "ỹ", "ýj": "ỵ",
"ỳs": "ý", "ỳr": "ỷ", "ỳx": "ỹ", "ỳj": "ỵ",
"ỷs": "ý", "ỷf": "ỳ", "ỷx": "ỹ", "ỷj": "ỵ",
"ỹs": "ý", "ỹf": "ỳ", "ỹr": "ỷ", "ỹj": "ỵ",
"ỵs": "ý", "ỵf": "ỳ", "ỵr": "ỷ", "ỵx": "ỹ",
"gias": "giá", "giaf": "già", "giar": "giả", "giax": "giã", "giaj": "giạ",
"gía": "giá", "gìa": "già", "gỉa": "giả", "gĩa": "giã", "gịa": "giạ",
"gíă": "giắ", "gìă": "giằ", "gỉă": "giẳ", "gĩă": "giẵ", "gịă": "giặ",
"gíâ": "giấ", "gìâ": "giầ", "gỉâ": "giẩ", "gĩẫ": "giẫ", "gịâ": "giậ",
"gíe": "gié", "gìe": "giè", "gỉe": "giẻ", "gĩe": "giẽ", "gịe": "giẹ",
"gíê": "giế", "gìê": "giề", "gỉê": "giể", "gĩê": "giễ", "gịê": "giệ",
"gío": "gió", "gìo": "giò", "gỉo": "giỏ", "gĩo": "giõ", "gịo": "giọ",
"gíô": "giố", "gìô": "giồ", "gỉô": "giổ", "gĩô": "giỗ", "gịô": "giộ",
"gíơ": "giớ", "gìơ": "giờ", "gỉơ": "giở", "gĩơ": "giỡ", "gịơ": "giợ",
"gius": "giú", "giuf": "giù", "giur": "giủ", "giux": "giũ", "giuj": "giụ",
"gíu": "giú", "gìu": "giù", "gỉu": "giủ", "gĩu": "giũ", "gịu": "giụ",
"gíư": "giứ", "gìư": "giừ", "gỉư": "giử", "gĩư": "giữ", "gịư": "giự",
"ghíê": "ghiế", "ghìê": "ghiề", "ghỉê": "ghiể", "ghĩê": "ghiễ", "ghịê": "ghiệ",
"acw": "ăc", "amw": "ăm", "anw": "ăn", "apw": "ăp", "atw": "ăt", "angw": "ăng",
"aca": "âc", "ama": "âm", "ana": "ân", "apa": "âp", "ata": "ât", "aua": "âu", "aya": "ây", "anga": "âng",
"eme": "êm", "ene": "ên", "epe": "êp", "ete": "êt", "enhe": "ênh",
"oio": "ôi","omo": "ôm", "ono": "ôn", "opo": "ôp", "oto": "ôt", "ongo": "ông",
"oiw": "ơi", "omw": "ơm", "onw": "ơn", "opw": "ơp", "otw": "ơt",
"uaw": "ưa", "uiw": "ưi", "umw": "ưm", "unw": "ưn", "utw": "ưt", "uuw": "ưu", "ungw": "ưng",
"uaw": "ưa", "ucw": "ưc", "uiw": "ưi", "umw": "ưm", "unw": "ưn", "utw": "ưt", "uuw": "ưu", "ungw": "ưng",
"ieme": "iêm", "iene": "iên", "iepe": "iêp", "iete": "iêt", "ieue": "iêu", "ienge": "iêng",
"uocw": "ươc", "uoiw": "ươi", "uomw": "ươm", "uonw": "ươn", "uotw": "ươt", "uongw": "ương",
"uoco": "uôc", "uoio": "uôi", "uomo": "uôm", "uono": "uôn", "uoto": "uôt", "uongo": "uông",
@@ -79,7 +156,7 @@
"ême": "eme", "êne": "ene", "êpe": "epe", "ête": "ete",
"ôio": "oio", "ômo": "omo", "ôno": "ono", "ôpo": "opo", "ôto": "oto", "ôngo": "ongo",
"ơmw": "omw", "ơnw": "onw", "ơpw": "opw", "ơtw": "otw",
"ưaw": "uaw", "ưiw": "uiw", "ưmw": "umw", "ưnw": "unw" , "ưtw": "utw", "ưuw": "uuw", "ưngw": "ungw",
"ưaw": "uaw", "ưcw": "ucw", "ưiw": "uiw", "ưmw": "umw", "ưnw": "unw" , "ưtw": "utw", "ưuw": "uuw", "ưngw": "ungw",
"iême": "ieme", "iêne": "iene", "iêpe": "iepe", "iête": "iete", "iêue": "ieue", "iênge": "ienge",
"ươcw": "uocw", "ươiw": "uoiw", "ươmw": "uomw", "ươnw": "uonw", "ươtw": "uotw", "ươngw": "uongw",
"uyêne": "uyene", "uyêt": "uyete",
@@ -138,6 +215,7 @@
"inhs": "ính", "inhf": "ình", "inhr": "ỉnh", "inhx": "ĩnh", "inhj": "ịnh",
"ías": "ias", "ìaf": "iaf", "ỉar": "iar", "ĩax": "iax", "ịaj": "iaj",
"iás": "ias", "iàf": "iaf", "iảr": "iar", "iãx": "iax", "iạj": "iaj",
"ícs": "ics", "ịcj": "icj",
"íms": "ims", "ìmf": "imf", "ỉmr": "imr", "ĩmx": "imx", "ịmj": "imj",
"íns": "ins", "ìnf": "inf", "ỉnr": "inr", "ĩnx": "inx", "ịnj": "inj",
@@ -385,6 +463,8 @@
"ưas": "ứa", "ưaf": "ừa", "ưar": "ửa", "ưax": "ữa", "ưaj": "ựa",
"úaw": "ứa", "ùaw": "ừa", "ủaw": "ửa", "ũaw": "ữa", "ụaw": "ựa",
"ưcs": "ức", "ưcj": "ực",
"úcw": "ức", "ụcw": "ực",
"ưis": "ứi", "ưif": "ừi", "ưir": "ửi", "ưix": "ữi", "ưij": "ựi",
"úiw": "ứi", "ùiw": "ừi", "ủiw": "ửi", "ũiw": "ữi", "ụiw": "ựi",
"ưms": "ứm", "ưmf": "ừm", "ưmr": "ửm", "ưmx": "ữm", "ưmj": "ựm",
@@ -403,6 +483,8 @@
"ửar": "ưar", "ửaw": "ủaw", "ưarw": "uarw", "ủawr": "uawr",
"ữax": "ưax", "ữaw": "ũaw", "ưaxw": "uaxw", "ũawx": "uawx",
"ựaj": "ưaj", "ựaw": "ụaw", "ưajw": "uajw", "ụawj": "uawj",
"ứcs": "ưcs", "ứcw": "úcw", "ưcsw": "ucsw", "úcws": "ucws",
"ựcj": "ưcj", "ựcw": "ụcw", "ưcjw": "ucjw", "ụcwj": "ucwj",
"ứis": "ưis", "ứiw": "úiw", "ưisw": "uisw", "úiws": "uiws",
"ừif": "ưif", "ừiw": "ùiw", "ưifw": "uifw", "ùiwf": "uiwf",
"ửir": "ưir", "ửiw": "ủiw", "ưirw": "uirw", "ủiwr": "uiwr",
@@ -450,6 +532,11 @@
"iénge": "iếng", "iènge": "iềng", "iẻnge": "iểng", "iẽnge": "iễng", "iẹnge": "iệng",
"iêngs": "iếng", "iêngf": "iềng", "iêngr": "iểng", "iêngx": "iễng", "iêngj": "iệng",
"iếs": "iês", "iếe": "iée", "iêse": "iese", "iées": "iees",
"iềf": "iêf", "iềe": "ièe", "iêfe": "iefe", "ièef": "ieef",
"iểr": "iêr", "iểe": "iẻe", "iêre": "iere", "iẻer": "ieer",
"iễx": "iêx", "iễe": "iẽe", "iêxe": "iexe", "iẽex": "ieex",
"iệj": "iêj", "iệe": "iẹe", "iêje": "ieje", "iẹej": "ieej",
"iếms": "iêms", "iếme": "iéme", "iêmse": "iemse", "iémes": "iemes",
"iềmf": "iêmf", "iềme": "ième", "iêmfe": "iemfe", "ièmef": "iemef",
"iểmr": "iêmr", "iểme": "iẻme", "iêmre": "iemre", "iẻmer": "iemer",

View File

@@ -104,12 +104,25 @@
"authors": [ "blucin" ],
"direction": "ltr"
},
{
"id": "colemak_dhm",
"label": "ColemakDHm",
"authors": [ "SteveP", "oneilljp" ],
"direction": "ltr"
},
{
"id": "danish",
"label": "Danish (QWERTY)",
"authors": [ "patrickgold" ],
"direction": "ltr"
},
{
"id": "diktor",
"label": "Diktor",
"authors": [ "kuroya2mouse" ],
"direction": "ltr",
"modifier": "org.florisboard.layouts:diktor"
},
{
"id": "dvorak",
"label": "Dvorak",
@@ -433,6 +446,12 @@
"label": "Workman",
"authors": [ "icyphox" ],
"direction": "ltr"
},
{
"id": "jcuken_interslavic",
"label": "Interslavic (ЈЦУКЕН)",
"authors": [ "victorbnl" ],
"direction": "ltr"
}
],
"charactersMod": [
@@ -454,6 +473,12 @@
"authors": [ "HeiWiper" ],
"direction": "rtl"
},
{
"id": "diktor",
"label": "Diktor",
"authors": [ "kuroya2mouse" ],
"direction": "ltr"
},
{
"id": "dvorak",
"label": "Dvorak",

View File

@@ -0,0 +1,49 @@
[
[
{ "$": "auto_text_key", "code": 1383, "label": "է" },
{ "$": "auto_text_key", "code": 1385, "label": "թ" },
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
{ "$": "auto_text_key", "code": 1393, "label": "ձ" },
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
{ "$": "auto_text_key", "code": 1408, "label": "ր" },
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
{ "$": "auto_text_key", "code": 1395, "label": "ճ" },
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
],
[
{ "$": "auto_text_key", "code": 1412, "label": "ք" },
{ "$": "auto_text_key", "code": 1400, "label": "ո" },
{ "$": "auto_text_key", "code": 1381, "label": "ե" },
{ "$": "auto_text_key", "code": 1404, "label": "ռ" },
{ "$": "auto_text_key", "code": 1407, "label": "տ" },
{ "$": "auto_text_key", "code": 1384, "label": "ը" },
{ "$": "auto_text_key", "code": 1410, "label": "ւ" },
{ "$": "auto_text_key", "code": 1387, "label": "ի" },
{ "$": "auto_text_key", "code": 1413, "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": 1379, "label": "գ" },
{ "$": "auto_text_key", "code": 1392, "label": "հ" },
{ "$": "auto_text_key", "code": 1397, "label": "յ" },
{ "$": "auto_text_key", "code": 1391, "label": "կ" },
{ "$": "auto_text_key", "code": 1388, "label": "լ" },
{ "$": "auto_text_key", "code": 1389, "label": "խ" }
],
[
{ "$": "auto_text_key", "code": 1382, "label": "զ" },
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
{ "$": "auto_text_key", "code": 1409, "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": "շ" }
]
]

View File

@@ -42,9 +42,9 @@
}
],
[
{ "$": "case_selector",
{ "$": "case_selector",
"lower": { "code": 2499, "label": "ৃ" },
"upper": { "$": "multi_text_key", "codePoints": [2480, 2509], "label": "র্" }
"upper": { "code": 2435, "label": "" }
},
{ "$": "case_selector",
"lower": { "code": 2497, "label": "ু" },
@@ -109,4 +109,4 @@
"upper": { "code": 2486, "label": "শ" }
}
]
]
]

View File

@@ -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": 122, "label": "z" },
{ "$": "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": 107, "label": "k" },
{ "$": "auto_text_key", "code": 104, "label": "h" }
]
]

View File

@@ -0,0 +1,49 @@
[
[
{ "$": "auto_text_key", "code": 1094, "label": "ц" },
{ "$": "auto_text_key", "code": 1100, "label": "ь" },
{ "$": "auto_text_key", "code": 1103, "label": "я" },
{ "$": "case_selector",
"lower": { "code": 44, "label": ",", "popup": {
"relevant": [
{ "code": 46, "label": "." }
]
} },
"upper": { "code": 46, "label": ".", "popup": {
"relevant": [
{ "code": 44, "label": "," }
]
} }
},
{ "$": "auto_text_key", "code": 1079, "label": "з" },
{ "$": "auto_text_key", "code": 1074, "label": "в" },
{ "$": "auto_text_key", "code": 1082, "label": "к" },
{ "$": "auto_text_key", "code": 1076, "label": "д" },
{ "$": "auto_text_key", "code": 1095, "label": "ч" },
{ "$": "auto_text_key", "code": 1096, "label": "ш" },
{ "$": "auto_text_key", "code": 1097, "label": "щ" }
],
[
{ "$": "auto_text_key", "code": 1091 , "label": "у" },
{ "$": "auto_text_key", "code": 1080 , "label": "и" },
{ "$": "auto_text_key", "code": 1077 , "label": "е" },
{ "$": "auto_text_key", "code": 1086 , "label": "о" },
{ "$": "auto_text_key", "code": 1072 , "label": "а" },
{ "$": "auto_text_key", "code": 1083 , "label": "л" },
{ "$": "auto_text_key", "code": 1085 , "label": "н" },
{ "$": "auto_text_key", "code": 1090 , "label": "т" },
{ "$": "auto_text_key", "code": 1089 , "label": "с" },
{ "$": "auto_text_key", "code": 1088 , "label": "р" },
{ "$": "auto_text_key", "code": 1081 , "label": "й" }
],
[
{ "$": "auto_text_key", "code": 1101 , "label": "э" },
{ "$": "auto_text_key", "code": 1093 , "label": "х" },
{ "$": "auto_text_key", "code": 1099 , "label": "ы" },
{ "$": "auto_text_key", "code": 1102 , "label": "ю" },
{ "$": "auto_text_key", "code": 1073 , "label": "б" },
{ "$": "auto_text_key", "code": 1084 , "label": "м" },
{ "$": "auto_text_key", "code": 1087 , "label": "п" },
{ "$": "auto_text_key", "code": 1075 , "label": "г" }
]
]

View File

@@ -0,0 +1,36 @@
[
[
{ "$": "auto_text_key", "code": 1112, "label": "ј" },
{ "$": "auto_text_key", "code": 1094, "label": "ц" },
{ "$": "auto_text_key", "code": 1091, "label": "у" },
{ "$": "auto_text_key", "code": 1082, "label": "к" },
{ "$": "auto_text_key", "code": 1077, "label": "е" },
{ "$": "auto_text_key", "code": 1085, "label": "н" },
{ "$": "auto_text_key", "code": 1114, "label": "њ" },
{ "$": "auto_text_key", "code": 1075, "label": "г" },
{ "$": "auto_text_key", "code": 1096, "label": "ш" },
{ "$": "auto_text_key", "code": 1079, "label": "з" },
{ "$": "auto_text_key", "code": 1093, "label": "х" }
],
[
{ "$": "auto_text_key", "code": 1092 , "label": "ф" },
{ "$": "auto_text_key", "code": 1099 , "label": "ы" },
{ "$": "auto_text_key", "code": 1074 , "label": "в" },
{ "$": "auto_text_key", "code": 1072 , "label": "а" },
{ "$": "auto_text_key", "code": 1087 , "label": "п" },
{ "$": "auto_text_key", "code": 1088 , "label": "р" },
{ "$": "auto_text_key", "code": 1086 , "label": "о" },
{ "$": "auto_text_key", "code": 1083 , "label": "л" },
{ "$": "auto_text_key", "code": 1113 , "label": "љ" },
{ "$": "auto_text_key", "code": 1078 , "label": "ж" }
],
[
{ "$": "auto_text_key", "code": 1108 , "label": "є" },
{ "$": "auto_text_key", "code": 1095 , "label": "ч" },
{ "$": "auto_text_key", "code": 1089 , "label": "с" },
{ "$": "auto_text_key", "code": 1084 , "label": "м" },
{ "$": "auto_text_key", "code": 1080 , "label": "и" },
{ "$": "auto_text_key", "code": 1090 , "label": "т" },
{ "$": "auto_text_key", "code": 1073 , "label": "б" }
]
]

View File

@@ -9,11 +9,7 @@
{ "$": "auto_text_key", "code": 1075, "label": "г" },
{ "$": "auto_text_key", "code": 1096, "label": "ш" },
{ "$": "auto_text_key", "code": 1097, "label": "щ" },
{ "code": 1079, "label": "з", "popup": {
"relevant": [
{ "code": 1247, "label": "ӟ" }
]
} },
{ "$": "auto_text_key", "code": 1079, "label": "з" },
{ "$": "auto_text_key", "code": 1093, "label": "х" }
],
[
@@ -23,34 +19,18 @@
{ "$": "auto_text_key", "code": 1072 , "label": "а" },
{ "$": "auto_text_key", "code": 1087 , "label": "п" },
{ "$": "auto_text_key", "code": 1088 , "label": "р" },
{ "$": "auto_text_key", "code": 1086 , "label": "о", "popup": {
"relevant": [
{ "code": 1255, "label": "ӧ" }
]
} },
{ "$": "auto_text_key", "code": 1086 , "label": "о" },
{ "$": "auto_text_key", "code": 1083 , "label": "л" },
{ "$": "auto_text_key", "code": 1076 , "label": "д" },
{ "$": "auto_text_key", "code": 1078 , "label": "ж", "popup": {
"relevant": [
{ "code": 1245, "label": "ӝ" }
]
} },
{ "$": "auto_text_key", "code": 1078 , "label": "ж" },
{ "$": "auto_text_key", "code": 1101 , "label": "э" }
],
[
{ "$": "auto_text_key", "code": 1103 , "label": "я" },
{ "$": "auto_text_key", "code": 1095 , "label": "ч", "popup": {
"relevant": [
{ "code": 1269, "label": "ӵ" }
]
} },
{ "$": "auto_text_key", "code": 1095 , "label": "ч" },
{ "$": "auto_text_key", "code": 1089 , "label": "с" },
{ "$": "auto_text_key", "code": 1084 , "label": "м" },
{ "$": "auto_text_key", "code": 1080 , "label": "и", "popup": {
"relevant": [
{ "code": 1253, "label": "ӥ" }
]
} },
{ "$": "auto_text_key", "code": 1080 , "label": "и" },
{ "$": "auto_text_key", "code": 1090 , "label": "т" },
{ "$": "auto_text_key", "code": 1100 , "label": "ь" },
{ "$": "auto_text_key", "code": 1073 , "label": "б" },

View File

@@ -0,0 +1,16 @@
[
[
{ "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" },
{ "$": "auto_text_key", "code": 1092, "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" },
{ "$": "auto_text_key", "code": 1078, "label": "ж", "groupId": 2 },
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]

View File

@@ -8,15 +8,13 @@
},
"half": { "code": 64, "label": "@" }
},
{ "code": 12306, "label": "〒", "popup": {
"main": { "code": 12320, "label": "〠" }
}
},
{
"$": "char_width_selector",
"full": { "code": 65283, "label": "", "popup": {
"main": { "code": 35, "label": "#" },
"relevant": [
{ "code": 12306, "label": "〒"},
{ "code": 12320, "label": "〠" },
{ "code": 8470, "label": "№" }
]
}
@@ -24,6 +22,8 @@
"half": { "code": 35, "label": "#", "popup": {
"main": { "code": 65283, "label": "" },
"relevant": [
{ "code": 12306, "label": "〒"},
{ "code": 12320, "label": "〠" },
{ "code": 8470, "label": "№" }
]
}
@@ -99,14 +99,18 @@
"full": { "code": 65291, "label": "", "popup": {
"main": { "code": 43, "label": "+" },
"relevant": [
{ "code": 177, "label": "±" }
{ "code": 177, "label": "±" },
{ "code": 61, "label": "=" },
{ "code": 65309, "label": "" }
]
}
},
"half": { "code": 43, "label": "+", "popup": {
"main": { "code": 65291, "label": "" },
"relevant": [
{ "code": 177, "label": "±" }
{ "code": 177, "label": "±" },
{ "code": 61, "label": "=" },
{ "code": 65309, "label": "" }
]
}
}
@@ -117,16 +121,20 @@
"main": { "code": 12302, "label": "『" },
"relevant": [
{ "code": 12304, "label": "【" },
{ "code": 12310, "label": "〖" }
{ "code": 12310, "label": "〖" },
{ "code": 65288, "label": "" },
{ "code": 65339, "label": "" }
]
}
},
"half": { "code": 65378, "label": "「", "popup": {
"main": { "code": 12301, "label": "" },
"main": { "code": 12300, "label": "" },
"relevant": [
{ "code": 12303, "label": "" },
{ "code": 12302, "label": "" },
{ "code": 12304, "label": "【" },
{ "code": 12310, "label": "〖" }
{ "code": 12310, "label": "〖" },
{ "code": 40, "label": "(" },
{ "code": 91, "label": "[" }
]
}
}
@@ -137,7 +145,9 @@
"main": { "code": 12303, "label": "』" },
"relevant": [
{ "code": 12305, "label": "】" },
{ "code": 12311, "label": "〗" }
{ "code": 12311, "label": "〗" },
{ "code": 65289, "label": "" },
{ "code": 65341, "label": "" }
]
}
},
@@ -146,7 +156,9 @@
"relevant": [
{ "code": 12303, "label": "』" },
{ "code": 12305, "label": "】" },
{ "code": 12311, "label": "〗" }
{ "code": 12311, "label": "〗" },
{ "code": 41, "label": ")" },
{ "code": 93, "label": "]" }
]
}
}

View File

@@ -54,7 +54,9 @@
]
} }
},
{ "code": 8730, "label": "√" },
{ "code": 8730, "label": "√", "popup": {
"main": { "code": 10003, "label": "✓" }
} },
{ "code": 960, "label": "π", "popup": {
"main": { "code": 928, "label": "Π" },
"relevant": [
@@ -104,7 +106,7 @@
{ "code": 61, "label": "=", "popup": {
"main": { "code": 8800, "label": "≠" },
"relevant": [
{ "code": 61, "label": "=" },
{ "code": 65309, "label": "" },
{ "code": 8734, "label": "∞" },
{ "code": 8776, "label": "≈" }
]

View File

@@ -6,15 +6,28 @@
],
[
{ "code": -201, "label": "view_characters", "type": "system_gui" },
{ "code": 12296, "label": "〈", "popup": {
"main": { "code": 12298, "label": "《" },
"relevant": [
{ "code": 8804, "label": "≤" },
{ "code": 8249, "label": "" },
{ "code": 10216, "label": "" },
{ "code": 65308, "label": "" }
]
} },
{ "$": "char_width_selector",
"full": { "code": 12296, "label": "〈", "popup": {
"main": { "code": 12298, "label": "《" },
"relevant": [
{ "code": 60, "label": "<" },
{ "code": 8804, "label": "" },
{ "code": 8249, "label": "" },
{ "code": 10216, "label": "⟨" },
{ "code": 65308, "label": "" }
]
} },
"half": { "code": 60, "label": "<", "popup": {
"main": { "code": 12298, "label": "《" },
"relevant": [
{ "code": 12296, "label": "〈" },
{ "code": 8804, "label": "≤" },
{ "code": 8249, "label": "" },
{ "code": 10216, "label": "⟨" },
{ "code": 65308, "label": "" }
]
} }
},
{ "code": -205, "label": "view_numeric_advanced", "type": "system_gui" },
{ "code": 12288, "label": "空白" },
{ "code": -9701, "label": "char_width_switcher", "type": "system_gui", "popup": {
@@ -24,15 +37,28 @@
]
}
},
{ "code": 12297, "label": "〉", "popup": {
"main": { "code": 12299, "label": "》" },
"relevant": [
{ "code": 62, "label": ">" },
{ "code": 8805, "label": "" },
{ "code": 10217, "label": "" },
{ "code": 65310, "label": "" }
]
} },
{ "$": "char_width_selector",
"full": { "code": 12297, "label": "〉", "popup": {
"main": { "code": 12299, "label": "》" },
"relevant": [
{ "code": 62, "label": ">" },
{ "code": 8805, "label": "" },
{ "code": 8250, "label": "" },
{ "code": 10217, "label": "⟩" },
{ "code": 65310, "label": "" }
]
} },
"half": { "code": 62, "label": ">", "popup": {
"main": { "code": 12299, "label": "》" },
"relevant": [
{ "code": 12297, "label": "〉" },
{ "code": 8805, "label": "≥" },
{ "code": 8250, "label": "" },
{ "code": 10217, "label": "⟩" },
{ "code": 65310, "label": "" }
]
} }
},
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
]
]

View File

@@ -8,11 +8,17 @@
{ "code": -201, "label": "view_characters", "type": "system_gui" },
{ "$": "char_width_selector",
"full": { "code": 12289, "label": "、", "popup": {
"main": { "code": 65292, "label": "" }
"main": { "code": 65292, "label": "" },
"relevant": [
{ "code": 44, "label": "," }
]
}
},
"half": { "code": 65380, "label": "、", "popup": {
"main": { "code": 44, "label": "," }
"main": { "code": 44, "label": "," },
"relevant": [
{ "code": 65292, "label": "" }
]
}
}
},

View File

@@ -31,6 +31,7 @@
{ "id": "bg", "authors": [ "iorvethe" ] },
{ "id": "bn-BD", "authors": [ "iamrasel" ] },
{ "id": "ca", "authors": [ "mikelloc" ] },
{ "id": "cjk", "authors": [ "moonbeamcelery" ] },
{ "id": "ckb", "authors": [ "GoRaN" ] },
{ "id": "cs", "authors": [ "stefan-misik" ] },
{ "id": "da", "authors": [ "patrickgold" ] },
@@ -72,6 +73,7 @@
{ "id": "sr", "authors": [ "hedidnothingwrong", "GrbavaCigla" ] },
{ "id": "sv", "authors": [ "patrickgold" ] },
{ "id": "tr", "authors": [ "kisekinopureya", "patrickgold", "dvrnynr" ] },
{ "id": "udm", "authors": [ "vorgoron" ] },
{ "id": "uk", "authors": [ "williamtheaker", "33kk", "honsiorovskyi" ] },
{ "id": "uk-cyr-ext", "authors": [ "williamtheaker", "33kk", "honsiorovskyi" ] },
{ "id": "ur-PK", "authors": [ "mubashir-rehman", "mirfatif" ] },
@@ -675,7 +677,7 @@
"suggestion": "org.florisboard.nlp.providers.han.shape"
},
"currencySet": "org.florisboard.currencysets:yen",
"popupMapping": "org.florisboard.localization:en",
"popupMapping": "org.florisboard.localization:cjk",
"preferred": {
"characters": "org.florisboard.layouts:qwerty",
"symbols": "org.florisboard.layouts:cjk",

View File

@@ -30,102 +30,97 @@
"ড়": {
"main": { "$": "auto_text_key", "code": 2525, "label": "ঢ়" }
},
"ৃ": {
"main": { "$": "auto_text_key", "code": 2443, "label": "ঋ" },
"relevant": [
{ "$": "auto_text_key", "code": 2500, "label": "ৄ" },
{ "$": "auto_text_key", "code": 2528, "label": "ৠ" },
{ "$": "auto_text_key", "code": 2529, "label": "ৡ" },
{ "$": "auto_text_key", "code": 2530, "label": "ৢ" },
{ "$": "auto_text_key", "code": 2531, "label": "ৣ" }
]
"ৃ": {
"main": { "$": "auto_text_key", "code": 2443, "label": "ঋ" }
},
"ু": {
"ু": {
"main": { "$": "auto_text_key", "code": 2441, "label": "উ" }
},
"ি": {
"ি": {
"main": { "$": "auto_text_key", "code": 2439, "label": "ই" }
},
"া": {
"া": {
"main": { "$": "auto_text_key", "code": 2438, "label": "আ" },
"relevant": [
"relevant": [
{ "$": "auto_text_key", "code": 2437, "label": "অ" }
]
},
"্": {
"্": {
"main": { "$": "auto_text_key", "code": 2433, "label": "ঁ" }
},
"ব": {
"ব": {
"main": { "$": "auto_text_key", "code": 2477, "label": "ভ" }
},
"ক": {
"ক": {
"main": { "$": "auto_text_key", "code": 2454, "label": "খ" }
},
"ত": {
"ত": {
"main": { "$": "auto_text_key", "code": 2469, "label": "থ" },
"relevant": [
"relevant": [
{ "$": "auto_text_key", "code": 2510, "label": "ৎ" }
]
},
"দ": {
"দ": {
"main": { "$": "auto_text_key", "code": 2471, "label": "ধ" }
},
"ো": {
"ো": {
"main": { "$": "auto_text_key", "code": 2451, "label": "ও" }
},
"ে": {
"ে": {
"main": { "$": "auto_text_key", "code": 2447, "label": "এ" }
},
"র": {
"র": {
"main": { "$": "auto_text_key", "code": 2482, "label": "ল" },
"relevant": [
"relevant": [
{ "code": -255, "label": "র‌্য" }
]
},
"ন": {
"ন": {
"main": { "$": "auto_text_key", "code": 2467, "label": "ণ" }
},
"স": {
"স": {
"main": { "$": "auto_text_key", "code": 2487, "label": "ষ" }
},
"ম": {
"ম": {
"main": { "$": "auto_text_key", "code": 2486, "label": "শ" }
},
"ূ": {
"ূ": {
"main": { "$": "auto_text_key", "code": 2442, "label": "ঊ" }
},
"ী": {
"ী": {
"main": { "$": "auto_text_key", "code": 2440, "label": "ঈ" }
},
"ঁ": {
"ঁ": {
"main": { "$": "auto_text_key", "code": 2492, "label": "়" },
"relevant": [
{ "$": "auto_text_key", "code": 2493, "label": "" },
{ "$": "auto_text_key", "code": 2544, "label": "" },
{ "$": "auto_text_key", "code": 2545, "label": "" },
{ "$": "auto_text_key", "code": 2492, "label": "" },
{ "$": "auto_text_key", "code": 2554, "label": "" },
{ "$": "auto_text_key", "code": 2519, "label": "" }
{ "$": "auto_text_key", "code": 2500, "label": "" },
{ "$": "auto_text_key", "code": 2530, "label": "" },
{ "$": "auto_text_key", "code": 2531, "label": "" },
{ "$": "auto_text_key", "code": 2528, "label": "" },
{ "$": "auto_text_key", "code": 2444, "label": "" },
{ "$": "auto_text_key", "code": 2529, "label": "" },
{ "$": "auto_text_key", "code": 2544, "label": "ৰ" },
{ "$": "auto_text_key", "code": 2545, "label": "ৱ" },
{ "$": "auto_text_key", "code": 2493, "label": "ঽ" },
{ "$": "auto_text_key", "code": 2554, "label": "৺" },
{ "$": "auto_text_key", "code": 2519, "label": "ৗ" }
]
},
"ৌ": {
"ৌ": {
"main": { "$": "auto_text_key", "code": 2452, "label": "ঔ" }
},
"ৈ": {
"ৈ": {
"main": { "$": "auto_text_key", "code": 2448, "label": "ঐ" }
},
"~right": {
"main": { "code": 2404, "label": "।" },
"relevant": [
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
{ "code": 34, "label": "\"" },
{ "code": 45, "label": "-" },
{ "code": 2435, "label": "" },
{ "code": 39, "label": "'" },
{ "code": 64, "label": "@" },
{ "code": 59, "label": ";" },
{ "code": 47, "label": "/" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
{ "code": 45, "label": "-" },
{ "code": 58, "label": ":" },
{ "code": 59, "label": ";" },
{ "code": 47, "label": "/" },
{ "$": "layout_direction_selector",
"ltr": { "code": 40, "label": "(" },
"rtl": { "code": 41, "label": "(" }
@@ -134,9 +129,13 @@
"ltr": { "code": 41, "label": ")" },
"rtl": { "code": 40, "label": ")" }
},
{ "code": 64, "label": "@" },
{ "code": 35, "label": "#" },
{ "code": 8205, "label": ">⁞<" },
{ "code": 8204, "label": "<⁞>" },
{ "code": 33, "label": "!" },
{ "code": 63, "label": "?" }
{ "code": 63, "label": "?" },
{ "code": 2405, "label": "॥" }
]
}
},

View File

@@ -0,0 +1,117 @@
{
"all": {
"a": {
"relevant": [
{ "$": "auto_text_key", "code": 257, "label": "ā" },
{ "$": "auto_text_key", "code": 225, "label": "á" },
{ "$": "auto_text_key", "code": 462, "label": "ǎ" },
{ "$": "auto_text_key", "code": 224, "label": "à" },
{ "$": "auto_text_key", "code": 230, "label": "æ" },
{ "$": "auto_text_key", "code": 227, "label": "ã" },
{ "$": "auto_text_key", "code": 229, "label": "å" },
{ "$": "auto_text_key", "code": 226, "label": "â" },
{ "$": "auto_text_key", "code": 228, "label": "ä" }
]
},
"c": {
"relevant": [
{ "$": "auto_text_key", "code": 231, "label": "ç" }
]
},
"e": {
"relevant": [
{ "$": "auto_text_key", "code": 275, "label": "ē" },
{ "$": "auto_text_key", "code": 233, "label": "é" },
{ "$": "auto_text_key", "code": 283, "label": "ě" },
{ "$": "auto_text_key", "code": 232, "label": "è" },
{ "$": "auto_text_key", "code": 234, "label": "ê" },
{ "$": "auto_text_key", "code": 235, "label": "ë" }
]
},
"i": {
"relevant": [
{ "$": "auto_text_key", "code": 299, "label": "ī" },
{ "$": "auto_text_key", "code": 237, "label": "í" },
{ "$": "auto_text_key", "code": 464, "label": "ǐ" },
{ "$": "auto_text_key", "code": 236, "label": "ì" },
{ "$": "auto_text_key", "code": 239, "label": "ï" },
{ "$": "auto_text_key", "code": 238, "label": "î" }
]
},
"n": {
"relevant": [
{ "$": "auto_text_key", "code": 241, "label": "ñ" },
{ "$": "auto_text_key", "code": 324, "label": "ń" }
]
},
"o": {
"relevant": [
{ "$": "auto_text_key", "code": 333, "label": "ō" },
{ "$": "auto_text_key", "code": 243, "label": "ó" },
{ "$": "auto_text_key", "code": 466, "label": "ǒ" },
{ "$": "auto_text_key", "code": 242, "label": "ò" },
{ "$": "auto_text_key", "code": 245, "label": "õ" },
{ "$": "auto_text_key", "code": 339, "label": "œ" },
{ "$": "auto_text_key", "code": 248, "label": "ø" },
{ "$": "auto_text_key", "code": 246, "label": "ö" },
{ "$": "auto_text_key", "code": 244, "label": "ô" }
]
},
"s": {
"relevant": [
{ "$": "auto_text_key", "code": 223, "label": "ß" }
]
},
"u": {
"relevant": [
{ "$": "auto_text_key", "code": 363, "label": "ū" },
{ "$": "auto_text_key", "code": 250, "label": "ú" },
{ "$": "auto_text_key", "code": 468, "label": "ǔ" },
{ "$": "auto_text_key", "code": 249, "label": "ù" },
{ "$": "auto_text_key", "code": 252, "label": "ü" },
{ "$": "auto_text_key", "code": 470, "label": "ǖ" },
{ "$": "auto_text_key", "code": 472, "label": "ǘ" },
{ "$": "auto_text_key", "code": 474, "label": "ǚ" },
{ "$": "auto_text_key", "code": 476, "label": "ǜ" },
{ "$": "auto_text_key", "code": 251, "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": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".net" }
]
}
}
}

View File

@@ -0,0 +1,46 @@
{
"all": {
"ե": {
"main": { "$": "auto_text_key", "code": 1415, "label": "և" }
},
"յ": {
"main": { "$": "auto_text_key", "code": 1416, "label": "ֈ" }
},
"ա": {
"main": { "$": "auto_text_key", "code": 1376, "label": "ՠ" }
},
"~right": {
"main": { "code": 44, "label": "," },
"relevant": [
{ "code": 1417, "label": "։" },
{ "code": 1418, "label": "֊" },
{ "code": 1369, "label": "ՙ" },
{ "code": 1370, "label": "՚" },
{ "code": 1373, "label": "՝" },
{ "code": 1371, "label": "՛" },
{ "code": 1375, "label": "՟" },
{ "code": 47, "label": "/" },
{ "code": 40, "label": "(" },
{ "code": 41, "label": ")" },
{ "code": 46, "label": "." },
{ "code": 1372, "label": "՜" },
{ "code": 33, "label": "!" },
{ "code": 63, "label": "?" },
{ "code": 1374, "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" }
]
}
}
}

View File

@@ -33,6 +33,7 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyboardManager
import dev.patrickgold.florisboard.ime.media.emoji.FlorisEmojiCompat
import dev.patrickgold.florisboard.ime.nlp.NlpManager
import dev.patrickgold.florisboard.ime.text.gestures.GlideTypingManager
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.lib.cache.CacheManager
import dev.patrickgold.florisboard.lib.crashutility.CrashUtility
@@ -40,9 +41,8 @@ import dev.patrickgold.florisboard.lib.devtools.Flog
import dev.patrickgold.florisboard.lib.devtools.LogTopic
import dev.patrickgold.florisboard.lib.devtools.flogError
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
import dev.patrickgold.florisboard.lib.io.AssetManager
import dev.patrickgold.florisboard.lib.io.deleteContentsRecursively
import dev.patrickgold.jetpref.datastore.JetPref
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
import org.florisboard.lib.kotlin.tryOrNull
import org.florisboard.libnative.dummyAdd
import java.lang.ref.WeakReference
@@ -61,13 +61,13 @@ class FlorisApplication : Application() {
System.loadLibrary("fl_native")
} catch (_: Exception) {
}
FlorisImeTheme.init()
}
}
private val prefs by florisPreferenceModel()
private val mainHandler by lazy { Handler(mainLooper) }
val assetManager = lazy { AssetManager(this) }
val cacheManager = lazy { CacheManager(this) }
val clipboardManager = lazy { ClipboardManager(this) }
val editorInstance = lazy { EditorInstance(this) }
@@ -144,8 +144,6 @@ private tailrec fun Context.florisApplication(): FlorisApplication {
fun Context.appContext() = lazyOf(this.florisApplication())
fun Context.assetManager() = this.florisApplication().assetManager
fun Context.cacheManager() = this.florisApplication().cacheManager
fun Context.clipboardManager() = this.florisApplication().clipboardManager

View File

@@ -10,49 +10,32 @@ import android.provider.MediaStore
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material.BottomSheetValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.SwipeableDefaults
import androidx.compose.material.rememberSwipeableState
import androidx.compose.material.swipeable
import androidx.compose.material3.BottomSheetDefaults
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.ime.sheet.BottomSheetHostUi
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
import dev.patrickgold.florisboard.lib.android.AndroidClipboardManager
import dev.patrickgold.florisboard.lib.android.stringRes
import dev.patrickgold.florisboard.lib.android.systemService
import dev.patrickgold.florisboard.app.apptheme.FlorisAppTheme
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.snygg.ui.snyggBackground
import dev.patrickgold.florisboard.lib.snygg.ui.snyggClip
import dev.patrickgold.florisboard.lib.snygg.ui.solidColor
import dev.patrickgold.florisboard.lib.snygg.ui.spSize
import kotlin.math.roundToInt
import dev.patrickgold.jetpref.datastore.model.observeAsState
import org.florisboard.lib.android.AndroidClipboardManager
import org.florisboard.lib.android.stringRes
import org.florisboard.lib.android.systemService
class FlorisCopyToClipboardActivity : ComponentActivity() {
private var error: CopyToClipboardError? = null
@@ -79,13 +62,14 @@ class FlorisCopyToClipboardActivity : ComponentActivity() {
super.onPause()
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val systemClipboardManager = this.systemService(AndroidClipboardManager::class)
val type = intent.type
val action = intent.action
val prefs by florisPreferenceModel()
if (Intent.ACTION_SEND != action || type == null) {
error = CopyToClipboardError.UNKNOWN_ERROR
} else {
@@ -116,77 +100,26 @@ class FlorisCopyToClipboardActivity : ComponentActivity() {
setContent {
ProvideLocalizedResources(this, forceLayoutDirection = LayoutDirection.Ltr) {
FlorisImeTheme {
BottomSheetHostUi(isShowing = true, onHide = { finish() }) {
val panelStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditor)
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorHeader)
val subheaderStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorSubheader)
val context = LocalContext.current
Swipable {
Column(
val theme by prefs.advanced.settingsTheme.observeAsState()
val isMaterialYouAware by prefs.advanced.useMaterialYou.observeAsState()
FlorisAppTheme(theme, isMaterialYouAware) {
BottomSheet {
Row {
Text(
text = error?.showError()
?: bitmap?.let { stringRes(id = R.string.send_to_clipboard__description__copied_image_to_clipboard) }
?: stringRes(R.string.send_to_clipboard__unknown_error),
textAlign = TextAlign.Center,
modifier = Modifier.weight(1f),
)
}
bitmap?.let {
Image(
modifier = Modifier
.snyggBackground(
context,
panelStyle,
fallbackColor = FlorisImeTheme.fallbackSurfaceColor()
)
.snyggClip(panelStyle)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.snyggBackground(context, headerStyle),
verticalAlignment = Alignment.CenterVertically,
) {
Spacer(modifier = Modifier.weight(1F))
BottomSheetDefaults.DragHandle(
color = headerStyle.foreground.solidColor(
context,
default = FlorisImeTheme.fallbackContentColor()
),
)
Spacer(modifier = Modifier.weight(1F))
}
Row(
modifier = Modifier
.fillMaxWidth()
.snyggBackground(context, headerStyle),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = error?.showError()
?: bitmap?.let { stringRes(id = R.string.send_to_clipboard__description__copied_image_to_clipboard) }
?: stringRes(R.string.send_to_clipboard__unknown_error),
color = headerStyle.foreground.solidColor(
context,
default = FlorisImeTheme.fallbackContentColor()
),
fontSize = headerStyle.fontSize.spSize(),
textAlign = TextAlign.Center,
modifier = Modifier.weight(1f),
)
Spacer(Modifier.height(48.dp))
}
bitmap?.let {
Image(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
bitmap = bitmap!!.asImageBitmap(),
contentDescription = null
)
}
Button(
onClick = { finish() },
modifier = Modifier.align(alignment = Alignment.End),
colors = ButtonDefaults.textButtonColors(
//containerColor = buttonContainer.background.solidColor(context = context),
contentColor = subheaderStyle.foreground.solidColor(context = context),
)
) {
Text(text = stringRes(id = R.string.action__ok))
}
}
.padding(start = 64.dp, end = 64.dp, top = 32.dp, bottom = 8.dp),
bitmap = bitmap!!.asImageBitmap(),
contentDescription = null
)
}
}
}
@@ -194,51 +127,28 @@ class FlorisCopyToClipboardActivity : ComponentActivity() {
}
}
@OptIn(ExperimentalMaterialApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun Swipable(
content: @Composable () -> Unit
internal fun BottomSheet(
content: @Composable ColumnScope.() -> Unit,
) {
val swipeableState = rememberSwipeableState(
initialValue = BottomSheetValue.Expanded,
confirmStateChange = {
if (it == BottomSheetValue.Collapsed) {
finish()
}
true
}
)
BoxWithConstraints {
val constraintsScope = this
val maxHeight = with(LocalDensity.current) {
constraintsScope.maxHeight.toPx()
}
Box(
modifier = Modifier
.swipeable(
state = swipeableState,
orientation = Orientation.Vertical,
anchors = mapOf(
0f to BottomSheetValue.Expanded,
maxHeight to BottomSheetValue.Collapsed,
),
resistance = SwipeableDefaults.resistanceConfig(
anchors = setOf(0f, maxHeight),
factorAtMin = 0F
)
)
.offset {
IntOffset(
x = 0,
y = swipeableState.offset.value.roundToInt()
)
}
) {
ModalBottomSheet(
modifier = Modifier.navigationBarsPadding(),
onDismissRequest = { finish() }
) {
Column {
content()
Button(
modifier = Modifier.align(Alignment.End).padding(16.dp),
onClick = { finish() },
colors = ButtonDefaults.textButtonColors(
//containerColor = buttonContainer.background.solidColor(context = context),
)
) {
Text(text = stringRes(id = R.string.action__ok))
}
}
}
}
}

View File

@@ -47,7 +47,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.ButtonDefaults
import androidx.compose.material3.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
@@ -97,14 +97,6 @@ import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionsEditorPa
import dev.patrickgold.florisboard.ime.text.TextInputLayout
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
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.showShortToast
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
@@ -113,16 +105,23 @@ 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 org.florisboard.lib.snygg.ui.SnyggSurface
import org.florisboard.lib.snygg.ui.shape
import org.florisboard.lib.snygg.ui.snyggBackground
import org.florisboard.lib.snygg.ui.snyggBorder
import org.florisboard.lib.snygg.ui.snyggShadow
import org.florisboard.lib.snygg.ui.solidColor
import org.florisboard.lib.snygg.ui.spSize
import dev.patrickgold.florisboard.lib.util.ViewUtils
import dev.patrickgold.florisboard.lib.util.debugSummarize
import dev.patrickgold.florisboard.lib.util.launchActivity
import dev.patrickgold.jetpref.datastore.model.observeAsState
import org.florisboard.lib.android.AndroidInternalR
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.isOrientationLandscape
import org.florisboard.lib.android.isOrientationPortrait
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.systemServiceOrNull
import org.florisboard.lib.kotlin.collectLatestIn
import java.lang.ref.WeakReference
@@ -273,9 +272,10 @@ class FlorisImeService : LifecycleInputMethodService() {
override fun onCreate() {
super.onCreate()
FlorisImeServiceReference = WeakReference(this)
WindowCompat.setDecorFitsSystemWindows(window.window!!, false)
subtypeManager.activeSubtypeFlow.collectLatestIn(lifecycleScope) { subtype ->
val config = Configuration(resources.configuration)
config.setLocale(subtype.primaryLocale)
config.setLocale(subtype.primaryLocale.base)
resourcesContext = createConfigurationContext(config)
}
}
@@ -402,6 +402,10 @@ class FlorisImeService : LifecycleInputMethodService() {
}
override fun onEvaluateFullscreenMode(): Boolean {
val config = resources.configuration
if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
return false
}
return when (prefs.keyboard.landscapeInputUiMode.get()) {
LandscapeInputUiMode.DYNAMICALLY_SHOW -> super.onEvaluateFullscreenMode()
LandscapeInputUiMode.NEVER_SHOW -> false
@@ -769,7 +773,7 @@ class FlorisImeService : LifecycleInputMethodService() {
?: "ACTION",
shape = actionStyle.shape.shape(),
colors = ButtonDefaults.buttonColors(
backgroundColor = actionStyle.background.solidColor(context, FlorisImeTheme.fallbackContentColor()),
containerColor = actionStyle.background.solidColor(context, FlorisImeTheme.fallbackContentColor()),
contentColor = actionStyle.foreground.solidColor(context, FlorisImeTheme.fallbackSurfaceColor()),
),
)

View File

@@ -37,6 +37,7 @@ import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
import dev.patrickgold.florisboard.ime.smartbar.CandidatesDisplayMode
import dev.patrickgold.florisboard.ime.smartbar.ExtendedActionsPlacement
import dev.patrickgold.florisboard.ime.smartbar.IncognitoDisplayMode
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionArrangement
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
@@ -45,10 +46,10 @@ import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.ime.theme.ThemeMode
import dev.patrickgold.florisboard.ime.theme.extCoreTheme
import dev.patrickgold.florisboard.lib.android.isOrientationPortrait
import org.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 org.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.util.VersionName
import dev.patrickgold.jetpref.datastore.JetPref
import dev.patrickgold.jetpref.datastore.model.PreferenceMigrationEntry
@@ -65,6 +66,10 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "advanced__settings_theme",
default = AppTheme.AUTO,
)
val useMaterialYou = boolean(
key = "advanced__use_material_you",
default = true,
)
val settingsLanguage = string(
key = "advanced__settings_language",
default = "auto",
@@ -471,6 +476,10 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "keyboard__space_bar_switches_to_characters",
default = true,
)
val incognitoDisplayMode = enum(
key = "keyboard__incognito_indicator",
default = IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD,
)
fun keyHintConfiguration(): KeyHintConfiguration {
return KeyHintConfiguration(
@@ -633,19 +642,11 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "theme__mode",
default = ThemeMode.FOLLOW_SYSTEM,
)
val dayThemeAdaptToApp = boolean(
key = "theme__day_theme_adapt_to_app",
default = false,
)
val dayThemeId = custom(
key = "theme__day_theme_id",
default = extCoreTheme("floris_day"),
serializer = ExtensionComponentName.Serializer,
)
val nightThemeAdaptToApp = boolean(
key = "theme__night_theme_adapt_to_app",
default = false,
)
val nightThemeId = custom(
key = "theme__night_theme_id",
default = extCoreTheme("floris_night"),

View File

@@ -0,0 +1,597 @@
package dev.patrickgold.florisboard.app
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
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.input.CapitalizationBehavior
import dev.patrickgold.florisboard.ime.input.HapticVibrationMode
import dev.patrickgold.florisboard.ime.input.InputFeedbackActivationMode
import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
import dev.patrickgold.florisboard.ime.keyboard.SpaceBarMode
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
import dev.patrickgold.florisboard.ime.smartbar.CandidatesDisplayMode
import dev.patrickgold.florisboard.ime.smartbar.ExtendedActionsPlacement
import dev.patrickgold.florisboard.ime.smartbar.IncognitoDisplayMode
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.ime.theme.ThemeMode
import dev.patrickgold.florisboard.lib.compose.stringRes
import org.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.jetpref.datastore.ui.ListPreferenceEntry
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
import org.florisboard.lib.kotlin.curlyFormat
import kotlin.reflect.KClass
private const val DEFAULT = ""
private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable () -> List<ListPreferenceEntry<*>>>(
AppTheme::class to DEFAULT to {
listPrefEntries {
entry(
key = AppTheme.AUTO,
label = stringRes(R.string.settings__system_default),
)
entry(
key = AppTheme.AUTO_AMOLED,
label = stringRes(R.string.pref__advanced__settings_theme__auto_amoled),
)
entry(
key = AppTheme.LIGHT,
label = stringRes(R.string.pref__advanced__settings_theme__light),
)
entry(
key = AppTheme.DARK,
label = stringRes(R.string.pref__advanced__settings_theme__dark),
)
entry(
key = AppTheme.AMOLED_DARK,
label = stringRes(R.string.pref__advanced__settings_theme__amoled_dark),
)
}
},
CandidatesDisplayMode::class to DEFAULT to {
listPrefEntries {
entry(
key = CandidatesDisplayMode.CLASSIC,
label = stringRes(R.string.enum__candidates_display_mode__classic),
)
entry(
key = CandidatesDisplayMode.DYNAMIC,
label = stringRes(R.string.enum__candidates_display_mode__dynamic),
)
entry(
key = CandidatesDisplayMode.DYNAMIC_SCROLLABLE,
label = stringRes(R.string.enum__candidates_display_mode__dynamic_scrollable),
)
}
},
CapitalizationBehavior::class to DEFAULT to {
listPrefEntries {
entry(
key = CapitalizationBehavior.CAPSLOCK_BY_DOUBLE_TAP,
label = stringRes(R.string.enum__capitalization_behavior__capslock_by_double_tap),
)
entry(
key = CapitalizationBehavior.CAPSLOCK_BY_CYCLE,
label = stringRes(R.string.enum__capitalization_behavior__capslock_by_cycle),
)
}
},
DisplayColorsAs::class to DEFAULT to {
listPrefEntries {
entry(
key = DisplayColorsAs.HEX8,
label = stringRes(R.string.enum__display_colors_as__hex8),
description = stringRes(R.string.general__example_given).curlyFormat("example" to "#4caf50ff"),
showDescriptionOnlyIfSelected = true,
)
entry(
key = DisplayColorsAs.RGBA,
label = stringRes(R.string.enum__display_colors_as__rgba),
description = stringRes(R.string.general__example_given).curlyFormat("example" to "rgba(76,175,80,1.0)"),
showDescriptionOnlyIfSelected = true,
)
}
},
DisplayKbdAfterDialogs::class to DEFAULT to {
listPrefEntries {
entry(
key = DisplayKbdAfterDialogs.ALWAYS,
label = stringRes(R.string.enum__display_kbd_after_dialogs__always),
description = stringRes(R.string.enum__display_kbd_after_dialogs__always__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = DisplayKbdAfterDialogs.NEVER,
label = stringRes(R.string.enum__display_kbd_after_dialogs__never),
description = stringRes(R.string.enum__display_kbd_after_dialogs__never__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = DisplayKbdAfterDialogs.REMEMBER,
label = stringRes(R.string.enum__display_kbd_after_dialogs__remember),
description = stringRes(R.string.enum__display_kbd_after_dialogs__remember__description),
showDescriptionOnlyIfSelected = true,
)
}
},
DisplayLanguageNamesIn::class to DEFAULT to {
listPrefEntries {
entry(
key = DisplayLanguageNamesIn.SYSTEM_LOCALE,
label = stringRes(R.string.enum__display_language_names_in__system_locale),
description = stringRes(R.string.enum__display_language_names_in__system_locale__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = DisplayLanguageNamesIn.NATIVE_LOCALE,
label = stringRes(R.string.enum__display_language_names_in__native_locale),
description = stringRes(R.string.enum__display_language_names_in__native_locale__description),
showDescriptionOnlyIfSelected = true,
)
}
},
EmojiSkinTone::class to DEFAULT to {
listPrefEntries {
entry(
key = EmojiSkinTone.DEFAULT,
label = stringRes(
R.string.enum__emoji_skin_tone__default,
"emoji" to "\uD83D\uDC4B" // 👋
),
)
entry(
key = EmojiSkinTone.LIGHT_SKIN_TONE,
label = stringRes(
R.string.enum__emoji_skin_tone__light_skin_tone,
"emoji" to "\uD83D\uDC4B\uD83C\uDFFB" // 👋🏻
),
)
entry(
key = EmojiSkinTone.MEDIUM_LIGHT_SKIN_TONE,
label = stringRes(
R.string.enum__emoji_skin_tone__medium_light_skin_tone,
"emoji" to "\uD83D\uDC4B\uD83C\uDFFC" // 👋🏼
),
)
entry(
key = EmojiSkinTone.MEDIUM_SKIN_TONE,
label = stringRes(
R.string.enum__emoji_skin_tone__medium_skin_tone,
"emoji" to "\uD83D\uDC4B\uD83C\uDFFD" // 👋🏽
),
)
entry(
key = EmojiSkinTone.MEDIUM_DARK_SKIN_TONE,
label = stringRes(
R.string.enum__emoji_skin_tone__medium_dark_skin_tone,
"emoji" to "\uD83D\uDC4B\uD83C\uDFFE" // 👋🏾
),
)
entry(
key = EmojiSkinTone.DARK_SKIN_TONE,
label = stringRes(
R.string.enum__emoji_skin_tone__dark_skin_tone,
"emoji" to "\uD83D\uDC4B\uD83C\uDFFF" // 👋🏿
),
)
}
},
ExtendedActionsPlacement::class to DEFAULT to {
listPrefEntries {
entry(
key = ExtendedActionsPlacement.ABOVE_CANDIDATES,
label = stringRes(R.string.enum__extended_actions_placement__above_candidates),
description = stringRes(R.string.enum__extended_actions_placement__above_candidates__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = ExtendedActionsPlacement.BELOW_CANDIDATES,
label = stringRes(R.string.enum__extended_actions_placement__below_candidates),
description = stringRes(R.string.enum__extended_actions_placement__below_candidates__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = ExtendedActionsPlacement.OVERLAY_APP_UI,
label = stringRes(R.string.enum__extended_actions_placement__overlay_app_ui),
description = stringRes(R.string.enum__extended_actions_placement__overlay_app_ui__description),
showDescriptionOnlyIfSelected = true,
)
}
},
HapticVibrationMode::class to DEFAULT to {
listPrefEntries {
entry(
key = HapticVibrationMode.USE_VIBRATOR_DIRECTLY,
label = stringRes(R.string.enum__haptic_vibration_mode__use_vibrator_directly),
description = stringRes(R.string.enum__haptic_vibration_mode__use_vibrator_directly__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = HapticVibrationMode.USE_HAPTIC_FEEDBACK_INTERFACE,
label = stringRes(R.string.enum__haptic_vibration_mode__use_haptic_feedback_interface),
description = stringRes(R.string.enum__haptic_vibration_mode__use_haptic_feedback_interface__description),
showDescriptionOnlyIfSelected = true,
)
}
},
KeyHintMode::class to DEFAULT to {
listPrefEntries {
entry(
key = KeyHintMode.ACCENT_PRIORITY,
label = stringRes(R.string.enum__key_hint_mode__accent_priority),
description = stringRes(R.string.enum__key_hint_mode__accent_priority__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = KeyHintMode.HINT_PRIORITY,
label = stringRes(R.string.enum__key_hint_mode__hint_priority),
description = stringRes(R.string.enum__key_hint_mode__hint_priority__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = KeyHintMode.SMART_PRIORITY,
label = stringRes(R.string.enum__key_hint_mode__smart_priority),
description = stringRes(R.string.enum__key_hint_mode__smart_priority__description),
showDescriptionOnlyIfSelected = true,
)
}
},
IncognitoDisplayMode::class to DEFAULT to {
listPrefEntries {
entry(
key = IncognitoDisplayMode.REPLACE_SHARED_ACTIONS_TOGGLE,
label = stringRes(id = R.string.enum__incognito_display_mode__replace_shared_actions_toggle),
)
entry(
key = IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD,
label = stringRes(id = R.string.enum__incognito_display_mode__display_behind_keyboard),
)
}
},
IncognitoMode::class to DEFAULT to {
listPrefEntries {
entry(
key = IncognitoMode.FORCE_OFF,
label = stringRes(R.string.enum__incognito_mode__force_off),
description = stringRes(R.string.enum__incognito_mode__force_off__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = IncognitoMode.DYNAMIC_ON_OFF,
label = stringRes(R.string.enum__incognito_mode__dynamic_on_off),
description = stringRes(R.string.enum__incognito_mode__dynamic_on_off__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = IncognitoMode.FORCE_ON,
label = stringRes(R.string.enum__incognito_mode__force_on),
description = stringRes(R.string.enum__incognito_mode__force_on__description),
showDescriptionOnlyIfSelected = true,
)
}
},
InputFeedbackActivationMode::class to "audio" to {
listPrefEntries {
entry(
key = InputFeedbackActivationMode.RESPECT_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__audio_respect_system_settings),
)
entry(
key = InputFeedbackActivationMode.IGNORE_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__audio_ignore_system_settings),
)
}
},
InputFeedbackActivationMode::class to "haptic" to {
listPrefEntries {
entry(
key = InputFeedbackActivationMode.RESPECT_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__haptic_respect_system_settings),
)
entry(
key = InputFeedbackActivationMode.IGNORE_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__haptic_ignore_system_settings),
)
}
},
LandscapeInputUiMode::class to DEFAULT to {
listPrefEntries {
entry(
key = LandscapeInputUiMode.NEVER_SHOW,
label = stringRes(R.string.enum__landscape_input_ui_mode__never_show),
)
entry(
key = LandscapeInputUiMode.ALWAYS_SHOW,
label = stringRes(R.string.enum__landscape_input_ui_mode__always_show),
)
entry(
key = LandscapeInputUiMode.DYNAMICALLY_SHOW,
label = stringRes(R.string.enum__landscape_input_ui_mode__dynamically_show),
)
}
},
OneHandedMode::class to DEFAULT to {
listPrefEntries {
entry(
key = OneHandedMode.OFF,
label = stringRes(R.string.enum__one_handed_mode__off),
)
entry(
key = OneHandedMode.START,
label = stringRes(R.string.enum__one_handed_mode__start),
)
entry(
key = OneHandedMode.END,
label = stringRes(R.string.enum__one_handed_mode__end),
)
}
},
SmartbarLayout::class to DEFAULT to {
listPrefEntries {
entry(
key = SmartbarLayout.SUGGESTIONS_ONLY,
label = stringRes(R.string.enum__smartbar_layout__suggestions_only),
description = stringRes(R.string.enum__smartbar_layout__suggestions_only__description),
)
entry(
key = SmartbarLayout.ACTIONS_ONLY,
label = stringRes(R.string.enum__smartbar_layout__actions_only),
description = stringRes(R.string.enum__smartbar_layout__actions_only__description),
)
entry(
key = SmartbarLayout.SUGGESTIONS_ACTIONS_SHARED,
label = stringRes(R.string.enum__smartbar_layout__suggestions_action_shared),
description = stringRes(R.string.enum__smartbar_layout__suggestions_action_shared__description),
)
entry(
key = SmartbarLayout.SUGGESTIONS_ACTIONS_EXTENDED,
label = stringRes(R.string.enum__smartbar_layout__suggestions_actions_extended),
description = stringRes(R.string.enum__smartbar_layout__suggestions_actions_extended__description),
)
}
},
SnyggLevel::class to DEFAULT to {
listPrefEntries {
entry(
key = SnyggLevel.BASIC,
label = stringRes(R.string.enum__snygg_level__basic),
description = stringRes(R.string.enum__snygg_level__basic__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = SnyggLevel.ADVANCED,
label = stringRes(R.string.enum__snygg_level__advanced),
description = stringRes(R.string.enum__snygg_level__advanced__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = SnyggLevel.DEVELOPER,
label = stringRes(R.string.enum__snygg_level__developer),
description = stringRes(R.string.enum__snygg_level__developer__description),
showDescriptionOnlyIfSelected = true,
)
}
},
SpaceBarMode::class to DEFAULT to {
listPrefEntries {
entry(
key = SpaceBarMode.NOTHING,
label = stringRes(R.string.enum__space_bar_mode__nothing),
)
entry(
key = SpaceBarMode.CURRENT_LANGUAGE,
label = stringRes(R.string.enum__space_bar_mode__current_language),
)
entry(
key = SpaceBarMode.SPACE_BAR_KEY,
label = stringRes(R.string.enum__space_bar_mode__space_bar_key),
)
}
},
SpellingLanguageMode::class to DEFAULT to {
listPrefEntries {
entry(
key = SpellingLanguageMode.USE_SYSTEM_LANGUAGES,
label = stringRes(R.string.enum__spelling_language_mode__use_system_languages),
)
entry(
key = SpellingLanguageMode.USE_KEYBOARD_SUBTYPES,
label = stringRes(R.string.enum__spelling_language_mode__use_keyboard_subtypes),
)
}
},
SwipeAction::class to "general" to {
listPrefEntries {
entry(
key = SwipeAction.NO_ACTION,
label = stringRes(R.string.enum__swipe_action__no_action),
)
entry(
key = SwipeAction.CYCLE_TO_PREVIOUS_KEYBOARD_MODE,
label = stringRes(R.string.enum__swipe_action__cycle_to_previous_keyboard_mode),
)
entry(
key = SwipeAction.CYCLE_TO_NEXT_KEYBOARD_MODE,
label = stringRes(R.string.enum__swipe_action__cycle_to_next_keyboard_mode),
)
entry(
key = SwipeAction.DELETE_WORD,
label = stringRes(R.string.enum__swipe_action__delete_word),
)
entry(
key = SwipeAction.HIDE_KEYBOARD,
label = stringRes(R.string.enum__swipe_action__hide_keyboard),
)
entry(
key = SwipeAction.INSERT_SPACE,
label = stringRes(R.string.enum__swipe_action__insert_space),
)
entry(
key = SwipeAction.MOVE_CURSOR_UP,
label = stringRes(R.string.enum__swipe_action__move_cursor_up),
)
entry(
key = SwipeAction.MOVE_CURSOR_DOWN,
label = stringRes(R.string.enum__swipe_action__move_cursor_down),
)
entry(
key = SwipeAction.MOVE_CURSOR_LEFT,
label = stringRes(R.string.enum__swipe_action__move_cursor_left),
)
entry(
key = SwipeAction.MOVE_CURSOR_RIGHT,
label = stringRes(R.string.enum__swipe_action__move_cursor_right),
)
entry(
key = SwipeAction.MOVE_CURSOR_START_OF_LINE,
label = stringRes(R.string.enum__swipe_action__move_cursor_start_of_line),
)
entry(
key = SwipeAction.MOVE_CURSOR_END_OF_LINE,
label = stringRes(R.string.enum__swipe_action__move_cursor_end_of_line),
)
entry(
key = SwipeAction.MOVE_CURSOR_START_OF_PAGE,
label = stringRes(R.string.enum__swipe_action__move_cursor_start_of_page),
)
entry(
key = SwipeAction.MOVE_CURSOR_END_OF_PAGE,
label = stringRes(R.string.enum__swipe_action__move_cursor_end_of_page),
)
entry(
key = SwipeAction.SHIFT,
label = stringRes(R.string.enum__swipe_action__shift),
)
entry(
key = SwipeAction.REDO,
label = stringRes(R.string.enum__swipe_action__redo),
)
entry(
key = SwipeAction.UNDO,
label = stringRes(R.string.enum__swipe_action__undo),
)
entry(
key = SwipeAction.SWITCH_TO_CLIPBOARD_CONTEXT,
label = stringRes(R.string.enum__swipe_action__switch_to_clipboard_context),
)
entry(
key = SwipeAction.SHOW_INPUT_METHOD_PICKER,
label = stringRes(R.string.enum__swipe_action__show_input_method_picker),
)
entry(
key = SwipeAction.SWITCH_TO_PREV_SUBTYPE,
label = stringRes(R.string.enum__swipe_action__switch_to_prev_subtype),
)
entry(
key = SwipeAction.SWITCH_TO_NEXT_SUBTYPE,
label = stringRes(R.string.enum__swipe_action__switch_to_next_subtype),
)
entry(
key = SwipeAction.SWITCH_TO_PREV_KEYBOARD,
label = stringRes(R.string.enum__swipe_action__switch_to_prev_keyboard),
)
entry(
key = SwipeAction.TOGGLE_SMARTBAR_VISIBILITY,
label = stringRes(R.string.enum__swipe_action__toggle_smartbar_visibility),
)
}
},
SwipeAction::class to "deleteSwipe" to {
listPrefEntries {
entry(
key = SwipeAction.NO_ACTION,
label = stringRes(R.string.enum__swipe_action__no_action),
)
entry(
key = SwipeAction.DELETE_CHARACTERS_PRECISELY,
label = stringRes(R.string.enum__swipe_action__delete_characters_precisely),
)
entry(
key = SwipeAction.DELETE_WORD,
label = stringRes(R.string.enum__swipe_action__delete_word),
)
entry(
key = SwipeAction.DELETE_WORDS_PRECISELY,
label = stringRes(R.string.enum__swipe_action__delete_words_precisely),
)
entry(
key = SwipeAction.SELECT_CHARACTERS_PRECISELY,
label = stringRes(R.string.enum__swipe_action__select_characters_precisely),
)
entry(
key = SwipeAction.SELECT_WORDS_PRECISELY,
label = stringRes(R.string.enum__swipe_action__select_words_precisely),
)
}
},
SwipeAction::class to "deleteLongPress" to {
listPrefEntries {
entry(
key = SwipeAction.DELETE_CHARACTER,
label = stringRes(R.string.enum__swipe_action__delete_character),
)
entry(
key = SwipeAction.DELETE_WORD,
label = stringRes(R.string.enum__swipe_action__delete_word),
)
}
},
ThemeMode::class to DEFAULT to {
listPrefEntries {
entry(
key = ThemeMode.ALWAYS_DAY,
label = stringRes(R.string.enum__theme_mode__always_day),
)
entry(
key = ThemeMode.ALWAYS_NIGHT,
label = stringRes(R.string.enum__theme_mode__always_night),
)
entry(
key = ThemeMode.FOLLOW_SYSTEM,
label = stringRes(R.string.enum__theme_mode__follow_system),
)
entry(
key = ThemeMode.FOLLOW_TIME,
label = stringRes(R.string.enum__theme_mode__follow_time),
)
}
},
UtilityKeyAction::class to DEFAULT to {
listPrefEntries {
entry(
key = UtilityKeyAction.SWITCH_TO_EMOJIS,
label = stringRes(R.string.enum__utility_key_action__switch_to_emojis),
)
entry(
key = UtilityKeyAction.SWITCH_LANGUAGE,
label = stringRes(R.string.enum__utility_key_action__switch_language),
)
entry(
key = UtilityKeyAction.SWITCH_KEYBOARD_APP,
label = stringRes(R.string.enum__utility_key_action__switch_keyboard_app),
)
entry(
key = UtilityKeyAction.DYNAMIC_SWITCH_LANGUAGE_EMOJIS,
label = stringRes(R.string.enum__utility_key_action__dynamic_switch_language_emojis),
)
}
},
)
@Composable
fun <V : Any> enumDisplayEntriesOf(
enumClass: KClass<V>,
variant: String = DEFAULT,
): List<ListPreferenceEntry<V>> {
@Suppress("UNCHECKED_CAST")
return ENUM_DISPLAY_ENTRIES[enumClass to variant]?.invoke()
as List<ListPreferenceEntry<V>>
}

View File

@@ -17,6 +17,7 @@
package dev.patrickgold.florisboard.app
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.os.Bundle
import androidx.activity.ComponentActivity
@@ -24,11 +25,11 @@ import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -41,16 +42,16 @@ import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.apptheme.FlorisAppTheme
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
import dev.patrickgold.florisboard.app.setup.NotificationPermissionState
import dev.patrickgold.florisboard.cacheManager
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 org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.hideAppIcon
import org.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
@@ -71,9 +72,11 @@ val LocalNavController = staticCompositionLocalOf<NavController> {
class FlorisAppActivity : ComponentActivity() {
private val prefs by florisPreferenceModel()
private val cacheManager by cacheManager()
private var appTheme by mutableStateOf(AppTheme.AUTO)
private var showAppIcon = true
private var resourcesContext by mutableStateOf(this as Context)
private var fileImportIntent by mutableStateOf<Intent?>(null)
override fun onCreate(savedInstanceState: Bundle?) {
// Splash screen should be installed before calling super.onCreate()
@@ -88,7 +91,8 @@ class FlorisAppActivity : ComponentActivity() {
}
prefs.advanced.settingsLanguage.observe(this) {
val config = Configuration(resources.configuration)
config.setLocale(if (it == "auto") FlorisLocale.default() else FlorisLocale.fromTag(it))
val locale = if (it == "auto") FlorisLocale.default() else FlorisLocale.fromTag(it)
config.setLocale(locale.base)
resourcesContext = createConfigurationContext(config)
}
if (AndroidVersion.ATMOST_API28_P) {
@@ -111,14 +115,15 @@ class FlorisAppActivity : ComponentActivity() {
AppVersionUtils.updateVersionOnInstallAndLastUse(this, prefs)
setContent {
ProvideLocalizedResources(resourcesContext) {
FlorisAppTheme(theme = appTheme) {
Surface(color = MaterialTheme.colors.background) {
SystemUiApp()
val useMaterialYou by prefs.advanced.useMaterialYou.observeAsState()
FlorisAppTheme(theme = appTheme, isMaterialYouAware = useMaterialYou) {
Surface(color = MaterialTheme.colorScheme.background) {
AppContent()
}
}
}
}
onNewIntent(intent)
}
}
@@ -136,6 +141,21 @@ class FlorisAppActivity : ComponentActivity() {
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
if (intent?.action == Intent.ACTION_VIEW && intent.data != null) {
fileImportIntent = intent
return
}
if (intent?.action == Intent.ACTION_SEND && intent.clipData != null) {
fileImportIntent = intent
return
}
fileImportIntent = null
}
@Composable
private fun AppContent() {
val navController = rememberNavController()
@@ -154,7 +174,7 @@ class FlorisAppActivity : ComponentActivity() {
) {
Column(
modifier = Modifier
.statusBarsPadding()
//.statusBarsPadding()
.navigationBarsPadding()
.imePadding(),
) {
@@ -168,6 +188,20 @@ class FlorisAppActivity : ComponentActivity() {
}
}
LaunchedEffect(fileImportIntent) {
val intent = fileImportIntent
if (intent != null) {
val data = if (intent.action == Intent.ACTION_VIEW) {
intent.data!!
} else {
intent.clipData!!.getItemAt(0).uri
}
val workspace = runCatching { cacheManager.readFromUriIntoCache(data) }.getOrNull()
navController.navigate(Routes.Ext.Import(ExtensionImportScreenType.EXT_ANY, workspace?.uuid))
}
fileImportIntent = null
}
SideEffect {
navController.setOnBackPressedDispatcher(this.onBackPressedDispatcher)
}

View File

@@ -27,8 +27,11 @@ import dev.patrickgold.florisboard.app.devtools.DevtoolsScreen
import dev.patrickgold.florisboard.app.devtools.ExportDebugLogScreen
import dev.patrickgold.florisboard.app.ext.ExtensionEditScreen
import dev.patrickgold.florisboard.app.ext.ExtensionExportScreen
import dev.patrickgold.florisboard.app.ext.ExtensionHomeScreen
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreen
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
import dev.patrickgold.florisboard.app.ext.ExtensionListScreen
import dev.patrickgold.florisboard.app.ext.ExtensionListScreenType
import dev.patrickgold.florisboard.app.ext.ExtensionViewScreen
import dev.patrickgold.florisboard.app.settings.HomeScreen
import dev.patrickgold.florisboard.app.settings.about.AboutScreen
@@ -58,7 +61,7 @@ import dev.patrickgold.florisboard.app.settings.typing.TypingScreen
import dev.patrickgold.florisboard.app.setup.SetupScreen
import org.florisboard.lib.kotlin.curlyFormat
@Suppress("FunctionName")
@Suppress("FunctionName", "ConstPropertyName")
object Routes {
object Setup {
const val Screen = "setup"
@@ -117,6 +120,14 @@ object Routes {
}
object Ext {
const val Home = "ext"
const val List = "ext/list/{type}?showUpdate={showUpdate}"
fun List(
type: ExtensionListScreenType,
showUpdate: Boolean
) = List.curlyFormat("type" to type.id, "showUpdate" to showUpdate)
const val Edit = "ext/edit/{id}?create={serial_type}"
fun Edit(id: String, serialType: String? = null): String {
return Edit.curlyFormat("id" to id, "serial_type" to (serialType ?: ""))
@@ -209,12 +220,20 @@ object Routes {
}
composable(Devtools.ExportDebugLog) { ExportDebugLogScreen() }
composable(Ext.Home) { ExtensionHomeScreen() }
composable(Ext.List) { navBackStack ->
val type = navBackStack.arguments?.getString("type")?.let { typeId ->
ExtensionListScreenType.entries.firstOrNull { it.id == typeId }
} ?: error("unknown type")
val showUpdate = navBackStack.arguments?.getString("showUpdate")
ExtensionListScreen(type, showUpdate == "true")
}
composable(Ext.Edit) { navBackStack ->
val extensionId = navBackStack.arguments?.getString("id")
val serialType = navBackStack.arguments?.getString("serial_type")
ExtensionEditScreen(
id = extensionId.toString(),
createSerialType = serialType.takeIf { it != null && it.isNotBlank() },
createSerialType = serialType.takeIf { !it.isNullOrBlank() },
)
}
composable(Ext.Export) { navBackStack ->

View File

@@ -18,7 +18,85 @@ package dev.patrickgold.florisboard.app.apptheme
import androidx.compose.ui.graphics.Color
/* Legacy Colors
val Green500 = Color(0xFF4CAF50)
val Green700 = Color(0xFF388E3C)
val Orange700 = Color(0xFFF57C00)
val Orange900 = Color(0xFFE65100)
*/
//Colors created with the material theme builder
val primaryLight = Color(0xFF006E1C)
val onPrimaryLight = Color(0xFFFFFFFF)
val primaryContainerLight = Color(0xFF58BC5B)
val onPrimaryContainerLight = Color(0xFF002204)
val secondaryLight = Color(0xFF005E16)
val onSecondaryLight = Color(0xFFFFFFFF)
val secondaryContainerLight = Color(0xFF2E8534)
val onSecondaryContainerLight = Color(0xFFFFFFFF)
val tertiaryLight = Color(0xFF964900)
val onTertiaryLight = Color(0xFFFFFFFF)
val tertiaryContainerLight = Color(0xFFFF8926)
val onTertiaryContainerLight = Color(0xFF341500)
val errorLight = Color(0xFFBA1A1A)
val onErrorLight = Color(0xFFFFFFFF)
val errorContainerLight = Color(0xFFFFDAD6)
val onErrorContainerLight = Color(0xFF410002)
val backgroundLight = Color(0xFFF5FBEF)
val onBackgroundLight = Color(0xFF171D16)
val surfaceLight = Color(0xFFF5FBEF)
val onSurfaceLight = Color(0xFF171D16)
val surfaceVariantLight = Color(0xFFDAE6D4)
val onSurfaceVariantLight = Color(0xFF3F4A3C)
val outlineLight = Color(0xFF6F7A6B)
val outlineVariantLight = Color(0xFFBECAB9)
val scrimLight = Color(0xFF000000)
val inverseSurfaceLight = Color(0xFF2C322A)
val inverseOnSurfaceLight = Color(0xFFEDF3E7)
val inversePrimaryLight = Color(0xFF78DC77)
val surfaceDimLight = Color(0xFFD6DCD0)
val surfaceBrightLight = Color(0xFFF5FBEF)
val surfaceContainerLowestLight = Color(0xFFFFFFFF)
val surfaceContainerLowLight = Color(0xFFF0F6EA)
val surfaceContainerLight = Color(0xFFEAF0E4)
val surfaceContainerHighLight = Color(0xFFE4EADE)
val surfaceContainerHighestLight = Color(0xFFDEE4D9)
val primaryDark = Color(0xFF78DC77)
val onPrimaryDark = Color(0xFF00390A)
val primaryContainerDark = Color(0xFF43A648)
val onPrimaryContainerDark = Color(0xFF000000)
val secondaryDark = Color(0xFF82DB7E)
val onSecondaryDark = Color(0xFF00390A)
val secondaryContainerDark = Color(0xFF2D8433)
val onSecondaryContainerDark = Color(0xFFFFFFFF)
val tertiaryDark = Color(0xFFFFB786)
val onTertiaryDark = Color(0xFF502400)
val tertiaryContainerDark = Color(0xFFEA7600)
val onTertiaryContainerDark = Color(0xFF030100)
val errorDark = Color(0xFFFFB4AB)
val onErrorDark = Color(0xFF690005)
val errorContainerDark = Color(0xFF93000A)
val onErrorContainerDark = Color(0xFFFFDAD6)
val backgroundDark = Color(0xFF0F120E)
val onBackgroundDark = Color(0xFFDEE4D9)
val surfaceDark = Color(0xFF0F120E)
val onSurfaceDark = Color(0xFFDEE4D9)
val surfaceVariantDark = Color(0xFF3F4A3C)
val onSurfaceVariantDark = Color(0xFFBECAB9)
val outlineDark = Color(0xFF899484)
val outlineVariantDark = Color(0xFF3F4A3C)
val scrimDark = Color(0xFF000000)
val inverseSurfaceDark = Color(0xFFDEE4D9)
val inverseOnSurfaceDark = Color(0xFF2C322A)
val inversePrimaryDark = Color(0xFF006E1C)
val surfaceDimDark = Color(0xFF0F150E)
val surfaceBrightDark = Color(0xFF353B33)
val surfaceContainerLowestDark = Color(0xFF0A1009)
val surfaceContainerLowDark = Color(0xFF171D16)
val surfaceContainerDark = Color(0xFF1B211A)
val surfaceContainerHighDark = Color(0xFF262C24)
val surfaceContainerHighestDark = Color(0xFF30362E)
val amoledDark = Color(0xFF000000)

View File

@@ -17,7 +17,7 @@
package dev.patrickgold.florisboard.app.apptheme
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Shapes
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp
val Shapes = Shapes(

View File

@@ -16,41 +16,50 @@
package dev.patrickgold.florisboard.app.apptheme
import android.app.Activity
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Colors
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import dev.patrickgold.florisboard.app.AppTheme
import org.florisboard.lib.android.AndroidVersion
private val AmoledDarkColorPalette = darkColors(
/*private val AmoledDarkColorPalette = darkColorScheme(
primary = Green500,
primaryVariant = Green700,
secondary = Orange700,
secondaryVariant = Orange900,
secondary = Green700,
tertiary = Orange700,
// = Orange900,
background = Color(0xFF000000),
surface = Color(0xFF212121),
)
private val DarkColorPalette = darkColors(
private val DarkColorPalette = darkColorScheme(
primary = Green500,
primaryVariant = Green700,
secondary = Orange700,
secondaryVariant = Orange900,
secondary = Green700,
tertiary = Orange700,
//secondaryVariant = Orange900,
background = Color(0xFF1F1F1F),
surface = Color(0xFF212121),
)
private val LightColorPalette = lightColors(
private val LightColorPalette = lightColorScheme(
primary = Green500,
primaryVariant = Green700,
secondary = Orange700,
secondaryVariant = Orange900,
secondary = Green700,
tertiary = Orange700,
//secondaryVariant = Orange900,
background = Color(0xFFFFFFFF),
surface = Color(0xFFE7E7E7),
@@ -63,35 +72,184 @@ private val LightColorPalette = lightColors(
onBackground = Color.Black,
onSurface = Color.Black,
*/
)*/
private val lightScheme = lightColorScheme(
primary = primaryLight,
onPrimary = onPrimaryLight,
primaryContainer = primaryContainerLight,
onPrimaryContainer = onPrimaryContainerLight,
secondary = secondaryLight,
onSecondary = onSecondaryLight,
secondaryContainer = secondaryContainerLight,
onSecondaryContainer = onSecondaryContainerLight,
tertiary = tertiaryLight,
onTertiary = onTertiaryLight,
tertiaryContainer = tertiaryContainerLight,
onTertiaryContainer = onTertiaryContainerLight,
error = errorLight,
onError = onErrorLight,
errorContainer = errorContainerLight,
onErrorContainer = onErrorContainerLight,
background = backgroundLight,
onBackground = onBackgroundLight,
surface = surfaceLight,
onSurface = onSurfaceLight,
surfaceVariant = surfaceVariantLight,
onSurfaceVariant = onSurfaceVariantLight,
outline = outlineLight,
outlineVariant = outlineVariantLight,
scrim = scrimLight,
inverseSurface = inverseSurfaceLight,
inverseOnSurface = inverseOnSurfaceLight,
inversePrimary = inversePrimaryLight,
surfaceDim = surfaceDimLight,
surfaceBright = surfaceBrightLight,
surfaceContainerLowest = surfaceContainerLowestLight,
surfaceContainerLow = surfaceContainerLowLight,
surfaceContainer = surfaceContainerLight,
surfaceContainerHigh = surfaceContainerHighLight,
surfaceContainerHighest = surfaceContainerHighestLight,
)
private val darkScheme = darkColorScheme(
primary = primaryDark,
onPrimary = onPrimaryDark,
primaryContainer = primaryContainerDark,
onPrimaryContainer = onPrimaryContainerDark,
secondary = secondaryDark,
onSecondary = onSecondaryDark,
secondaryContainer = secondaryContainerDark,
onSecondaryContainer = onSecondaryContainerDark,
tertiary = tertiaryDark,
onTertiary = onTertiaryDark,
tertiaryContainer = tertiaryContainerDark,
onTertiaryContainer = onTertiaryContainerDark,
error = errorDark,
onError = onErrorDark,
errorContainer = errorContainerDark,
onErrorContainer = onErrorContainerDark,
background = backgroundDark,
onBackground = onBackgroundDark,
surface = surfaceDark,
onSurface = onSurfaceDark,
surfaceVariant = surfaceVariantDark,
onSurfaceVariant = onSurfaceVariantDark,
outline = outlineDark,
outlineVariant = outlineVariantDark,
scrim = scrimDark,
inverseSurface = inverseSurfaceDark,
inverseOnSurface = inverseOnSurfaceDark,
inversePrimary = inversePrimaryDark,
surfaceDim = surfaceDimDark,
surfaceBright = surfaceBrightDark,
surfaceContainerLowest = surfaceContainerLowestDark,
surfaceContainerLow = surfaceContainerLowDark,
surfaceContainer = surfaceContainerDark,
surfaceContainerHigh = surfaceContainerHighDark,
surfaceContainerHighest = surfaceContainerHighestDark,
)
private val amoledScheme = darkScheme.copy(
background = amoledDark,
surface = amoledDark
)
@Composable
fun FlorisAppTheme(
theme: AppTheme,
isMaterialYouAware: Boolean,
content: @Composable () -> Unit
) {
val colors = when (theme) {
AppTheme.AUTO -> when {
isSystemInDarkTheme() -> DarkColorPalette
else -> LightColorPalette
val colors = if (AndroidVersion.ATLEAST_API31_S) {
when (theme) {
AppTheme.AUTO -> when {
isMaterialYouAware -> when {
isSystemInDarkTheme() -> dynamicDarkColorScheme(LocalContext.current)
else -> dynamicLightColorScheme(LocalContext.current)
}
else -> {
when {
isSystemInDarkTheme() -> darkScheme
else -> lightScheme
}
}
}
AppTheme.AUTO_AMOLED -> when {
isMaterialYouAware -> when {
isSystemInDarkTheme() -> dynamicDarkColorScheme(LocalContext.current).copy(
background = amoledDark,
surface = amoledDark,
)
else -> dynamicLightColorScheme(LocalContext.current)
}
else -> {
when {
isSystemInDarkTheme() -> amoledScheme
else -> lightScheme
}
}
}
AppTheme.LIGHT -> when {
isMaterialYouAware -> dynamicLightColorScheme(LocalContext.current)
else -> lightScheme
}
AppTheme.DARK -> when {
isMaterialYouAware -> dynamicDarkColorScheme(LocalContext.current)
else -> darkScheme
}
AppTheme.AMOLED_DARK -> when {
isMaterialYouAware -> dynamicDarkColorScheme(LocalContext.current).copy(
background = amoledDark,
surface = amoledDark,
)
else -> amoledScheme
}
}
AppTheme.AUTO_AMOLED -> when {
isSystemInDarkTheme() -> AmoledDarkColorPalette
else -> LightColorPalette
} else {
when (theme) {
AppTheme.AUTO -> when {
isSystemInDarkTheme() -> darkScheme
else -> lightScheme
}
AppTheme.AUTO_AMOLED -> when {
isSystemInDarkTheme() -> darkScheme
else -> lightScheme
}
AppTheme.LIGHT -> lightScheme
AppTheme.DARK -> darkScheme
AppTheme.AMOLED_DARK -> amoledScheme
}
}
val darkTheme =
theme == AppTheme.DARK
|| theme == AppTheme.AMOLED_DARK
|| (theme == AppTheme.AUTO && isSystemInDarkTheme())
|| (theme == AppTheme.AUTO_AMOLED && isSystemInDarkTheme())
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = !darkTheme
}
AppTheme.LIGHT -> LightColorPalette
AppTheme.DARK -> DarkColorPalette
AppTheme.AMOLED_DARK -> AmoledDarkColorPalette
}
MaterialTheme(
colors = colors,
colorScheme = colors,
typography = Typography,
shapes = Shapes,
content = content,
)
}
val Colors.outline: Color
@Composable
get() = this.onSurface.copy(alpha = ButtonDefaults.OutlinedBorderOpacity)

View File

@@ -16,7 +16,7 @@
package dev.patrickgold.florisboard.app.apptheme
import androidx.compose.material.Typography
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
@@ -24,7 +24,7 @@ import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
body1 = TextStyle(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp

View File

@@ -21,26 +21,25 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.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.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontFamily
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
import dev.patrickgold.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.io.subDir
import dev.patrickgold.florisboard.lib.io.subFile
import dev.patrickgold.jetpref.datastore.model.observeAsState
import java.util.*
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.kotlin.io.subDir
import org.florisboard.lib.kotlin.io.subFile
import java.util.Locale
@Composable
fun AndroidLocalesScreen() = FlorisScreen {

View File

@@ -19,7 +19,7 @@ package dev.patrickgold.florisboard.app.devtools
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -27,7 +27,7 @@ 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.lib.android.AndroidSettings
import org.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

View File

@@ -21,8 +21,8 @@ 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.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState

View File

@@ -27,8 +27,8 @@ import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.extensionManager
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.android.showLongToast
import org.florisboard.lib.android.AndroidSettings
import org.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.compose.FlorisConfirmDeleteDialog
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.stringRes

View File

@@ -21,7 +21,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
@@ -37,7 +37,7 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.sp
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.showShortToast
import dev.patrickgold.florisboard.lib.compose.FlorisButton
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll

View File

@@ -0,0 +1,93 @@
package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Shop
import androidx.compose.material.icons.outlined.FileDownload
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.lib.util.launchUrl
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
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.generateUpdateUrl
import org.florisboard.lib.kotlin.curlyFormat
@Composable
fun UpdateBox(extensionIndex: List<Extension>) {
val context = LocalContext.current
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
) {
Text(
modifier = Modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp, bottom = 4.dp),
text = stringRes(id = R.string.ext__update_box__internet_permission_hint),
style = MaterialTheme.typography.bodySmall,
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
FlorisTextButton(
onClick = {
context.launchUrl(extensionIndex.generateUpdateUrl(version = "v~draft2", host = "fladdonstest.patrickgold.dev"))
},
icon = Icons.Outlined.FileDownload,
text = stringRes(id = R.string.ext__update_box__search_for_updates)
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
@Composable
fun AddonManagementReferenceBox(
type: ExtensionListScreenType
) {
val navController = LocalNavController.current
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
title = stringRes(id = R.string.ext__addon_management_box__managing_placeholder).curlyFormat(
"extensions" to type.let { stringRes(id = it.titleResId).lowercase() }
)
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
text = stringRes(id = R.string.ext__addon_management_box__addon_manager_info),
style = MaterialTheme.typography.bodySmall,
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
Spacer(modifier = Modifier.weight(1f))
FlorisTextButton(
onClick = {
val route = Routes.Ext.List(type, showUpdate = true)
navController.navigate(
route
)
},
icon = Icons.Default.Shop,
text = stringRes(id = R.string.ext__addon_management_box__go_to_page).curlyFormat(
"ext_home_title" to stringRes(type.titleResId),
),
)
}
}
}

View File

@@ -21,21 +21,18 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ListItem
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ListItem
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
@@ -97,8 +94,8 @@ fun ExtensionComponentView(
}
Text(
text = text,
style = MaterialTheme.typography.body2,
color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current,
)
}
is LanguagePackComponent -> {
@@ -113,8 +110,8 @@ fun ExtensionComponentView(
}
Text(
text = text,
style = MaterialTheme.typography.body2,
color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current,
)
}
else -> { }
@@ -132,7 +129,7 @@ fun ExtensionComponentView(
icon = Icons.Default.Delete,
text = stringRes(R.string.action__delete),
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colors.error,
contentColor = MaterialTheme.colorScheme.error,
),
)
}
@@ -149,7 +146,6 @@ fun ExtensionComponentView(
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun <T : ExtensionComponent> ExtensionComponentListView(
modifier: Modifier = Modifier,
@@ -160,19 +156,19 @@ fun <T : ExtensionComponent> ExtensionComponentListView(
) {
Column(modifier = modifier) {
ListItem(
text = { Text(
headlineContent = { Text(
text = title,
color = MaterialTheme.colors.secondary,
color = MaterialTheme.colorScheme.secondary,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
) },
trailing = if (onCreateBtnClick != null) {
trailingContent = if (onCreateBtnClick != null) {
@Composable {
FlorisIconButton(
onClick = onCreateBtnClick,
icon = Icons.Default.Add,
iconColor = MaterialTheme.colors.secondary,
iconColor = MaterialTheme.colorScheme.secondary,
)
}
} else { null },

View File

@@ -28,14 +28,14 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.outlined.LibraryBooks
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -47,7 +47,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
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
@@ -60,7 +59,6 @@ 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.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
@@ -69,7 +67,6 @@ 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
@@ -85,15 +82,16 @@ 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 org.florisboard.lib.snygg.SnyggStylesheetJsonConfig
import dev.patrickgold.florisboard.themeManager
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.vectorResource
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import java.util.*
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.kotlin.io.subFile
import org.florisboard.lib.kotlin.io.writeJson
import java.util.UUID
import kotlin.reflect.KClass
private val TextFieldVerticalPadding = 8.dp
@@ -300,8 +298,7 @@ private fun EditScreen(
navigationIcon {
FlorisIconButton(
onClick = { handleBackPress() },
modifier = Modifier.autoMirrorForRtl(),
icon = Icons.Default.ArrowBack,
icon = Icons.AutoMirrored.Filled.ArrowBack,
)
}
@@ -863,7 +860,7 @@ private fun EditorSheetTextField(
showValidationError: Boolean = false,
validationResult: ValidationResult? = null,
) {
val borderColor = MaterialTheme.colors.outline
val borderColor = MaterialTheme.colorScheme.outline
Column(modifier = Modifier.padding(vertical = TextFieldVerticalPadding)) {
Row(
modifier = Modifier
@@ -872,14 +869,14 @@ private fun EditorSheetTextField(
) {
Text(
text = label,
style = MaterialTheme.typography.subtitle2,
style = MaterialTheme.typography.titleSmall,
)
if (isRequired) {
Text(
modifier = Modifier.padding(start = 2.dp),
text = "*",
style = MaterialTheme.typography.subtitle2,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.error,
)
}
}
@@ -891,7 +888,7 @@ private fun EditorSheetTextField(
singleLine = singleLine,
showValidationError = showValidationError,
validationResult = validationResult,
colors = TextFieldDefaults.outlinedTextFieldColors(
colors = OutlinedTextFieldDefaults.colors(
unfocusedBorderColor = borderColor,
disabledBorderColor = borderColor,
)

View File

@@ -23,7 +23,7 @@ import androidx.compose.ui.platform.LocalContext
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.lib.android.showLongToast
import org.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.ext.Extension
import dev.patrickgold.florisboard.lib.ext.ExtensionDefaults

View File

@@ -0,0 +1,101 @@
package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Input
import androidx.compose.material.icons.filled.Keyboard
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.Shop
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
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.Routes
import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.lib.util.launchUrl
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
@Composable
fun ExtensionHomeScreen() = FlorisScreen {
title = stringRes(R.string.ext__home__title)
previewFieldVisible = false
val context = LocalContext.current
val navController = LocalNavController.current
val extensionManager by context.extensionManager()
val extensionIndex = extensionManager.combinedExtensionList()
content {
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
) {
Text(
modifier = Modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp, bottom = 4.dp),
text = stringRes(id = R.string.ext__home__info),
style = MaterialTheme.typography.bodySmall,
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
FlorisTextButton(
onClick = {
context.launchUrl("https://${BuildConfig.FLADDONS_STORE_URL}/")
},
icon = Icons.Default.Shop,
text = stringRes(id = R.string.ext__home__visit_store),
)
Spacer(modifier = Modifier.weight(1f))
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.Import(ExtensionImportScreenType.EXT_ANY, null))
},
icon = Icons.AutoMirrored.Filled.Input,
text = stringRes(R.string.action__import),
)
}
}
UpdateBox(extensionIndex = extensionIndex)
PreferenceGroup(title = stringRes(id = R.string.ext__home__visit_store)) {
Preference(
icon = Icons.Default.Palette,
title = stringRes(R.string.ext__list__ext_theme),
onClick = {
navController.navigate(Routes.Ext.List(ExtensionListScreenType.EXT_THEME,false))
},
)
Preference(
icon = Icons.Default.Keyboard,
title = stringRes(R.string.ext__list__ext_keyboard),
onClick = {
navController.navigate(Routes.Ext.List(ExtensionListScreenType.EXT_KEYBOARD,false))
},
)
Preference(
icon = Icons.Default.Language,
title = stringRes(R.string.ext__list__ext_languagepack),
onClick = {
navController.navigate(Routes.Ext.List(ExtensionListScreenType.EXT_LANGUAGEPACK,false))
},
)
}
}
}

View File

@@ -29,14 +29,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -51,7 +50,7 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyboardExtension
import dev.patrickgold.florisboard.ime.nlp.LanguagePackExtension
import dev.patrickgold.florisboard.ime.theme.ThemeExtension
import dev.patrickgold.florisboard.lib.NATIVE_NULLPTR
import dev.patrickgold.florisboard.lib.android.showLongToast
import org.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
@@ -100,12 +99,6 @@ fun ExtensionImportScreen(type: ExtensionImportScreenType, initUuid: String?) =
val cacheManager by context.cacheManager()
val extensionManager by context.extensionManager()
val initWsUuid by rememberSaveable { mutableStateOf(initUuid) }
var importResult by remember {
val workspace = initWsUuid?.let { cacheManager.importer.getWorkspaceByUuid(it) }?.let { resultOk(it) }
mutableStateOf(workspace)
}
fun getSkipReason(fileInfo: CacheManager.FileInfo): Int {
return when {
!FileRegistry.matchesFileFilter(fileInfo, type.supportedFiles) -> {
@@ -119,29 +112,37 @@ fun ExtensionImportScreen(type: ExtensionImportScreenType, initUuid: String?) =
NATIVE_NULLPTR.toInt()
}
}
fileInfo.mediaType == FileRegistry.FlexExtension.mediaType -> {
else -> { // ext == null
R.string.ext__import__file_skip_ext_corrupted
}
else -> {
NATIVE_NULLPTR.toInt()
}
}
}
fun Result<CacheManager.ImporterWorkspace>.mapSkipReasons(): Result<CacheManager.ImporterWorkspace> {
return this.map { workspace ->
workspace.inputFileInfos.forEach { fileInfo ->
fileInfo.skipReason = getSkipReason(fileInfo)
}
workspace
}
}
var importResult by remember(initUuid) {
val workspace = initUuid?.let { cacheManager.importer.getWorkspaceByUuid(it) }
?.let { resultOk(it) }
?.mapSkipReasons()
mutableStateOf(workspace)
}
val importLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetMultipleContents(),
onResult = { uriList ->
// If uri is null it indicates that the selection activity
// was cancelled (mostly by pressing the back button), so
// we don't display an error message here.
if (uriList.isNullOrEmpty()) return@rememberLauncherForActivityResult
if (uriList.isEmpty()) return@rememberLauncherForActivityResult
importResult?.getOrNull()?.close()
importResult = runCatching { cacheManager.readFromUriIntoCache(uriList) }.map { workspace ->
workspace.inputFileInfos.forEach { fileInfo ->
fileInfo.skipReason = getSkipReason(fileInfo)
}
workspace
}
importResult = runCatching { cacheManager.readFromUriIntoCache(uriList) }.mapSkipReasons()
},
)
@@ -197,15 +198,17 @@ fun ExtensionImportScreen(type: ExtensionImportScreenType, initUuid: String?) =
}
content {
FlorisOutlinedButton(
onClick = {
importLauncher.launch("*/*")
},
modifier = Modifier
.padding(vertical = 16.dp)
.align(Alignment.CenterHorizontally),
text = stringRes(R.string.action__select_files),
)
if (initUuid == null) {
FlorisOutlinedButton(
onClick = {
importLauncher.launch("*/*")
},
modifier = Modifier
.padding(vertical = 16.dp)
.align(Alignment.CenterHorizontally),
text = stringRes(R.string.action__select_files),
)
}
val result = importResult
when {
@@ -228,8 +231,8 @@ fun ExtensionImportScreen(type: ExtensionImportScreenType, initUuid: String?) =
Text(
modifier = Modifier.padding(horizontal = 16.dp),
text = stringRes(R.string.ext__import__error_unexpected_exception),
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error,
)
SelectionContainer {
Text(
@@ -237,8 +240,8 @@ fun ExtensionImportScreen(type: ExtensionImportScreenType, initUuid: String?) =
.florisHorizontalScroll()
.padding(horizontal = 16.dp),
text = result.exceptionOrNull()?.stackTraceToString() ?: "null",
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error,
fontStyle = FontStyle.Italic,
)
}
@@ -266,20 +269,20 @@ private fun FileInfoView(
Row {
Text(
text = Formatter.formatShortFileSize(LocalContext.current, fileInfo.size),
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
color = grayColor,
)
if (ext != null) {
FlorisBulletSpacer()
Text(
text = ext.meta.id,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
color = grayColor,
)
FlorisBulletSpacer()
Text(
text = ext.meta.version,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
color = grayColor,
)
}
@@ -288,12 +291,12 @@ private fun FileInfoView(
Spacer(modifier = Modifier.height(8.dp))
Text(
text = ext.meta.title,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
)
ext.meta.description?.let { description ->
Text(
text = description,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
fontStyle = FontStyle.Italic,
)
}
@@ -303,13 +306,13 @@ private fun FileInfoView(
}
Text(
text = stringRes(R.string.ext__meta__maintainers_by, "maintainers" to maintainers),
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
)
Spacer(modifier = Modifier.height(8.dp))
for (component in ext.components()) {
Text(
text = component.id,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
)
}
}
@@ -318,16 +321,16 @@ private fun FileInfoView(
.fillMaxWidth()
.height(19.dp)
.padding(top = 10.dp, bottom = 8.dp)
.background(MaterialTheme.colors.error.copy(alpha = 0.56f)))
.background(MaterialTheme.colorScheme.error.copy(alpha = 0.56f)))
Text(
text = stringRes(R.string.ext__import__file_skip),
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error,
)
Text(
text = stringRes(fileInfo.skipReason),
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error,
fontStyle = FontStyle.Italic,
)
}

View File

@@ -17,13 +17,11 @@
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.lib.compose.FlorisChip
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ExtensionKeywordChip(
keyword: String,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2024 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,84 +16,135 @@
package dev.patrickgold.florisboard.app.ext
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.ime.theme.ThemeExtension
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
import dev.patrickgold.florisboard.lib.observeAsNonNullState
enum class ExtensionListScreenType(
val id: String,
@StringRes val titleResId: Int,
val getExtensionIndex: (ExtensionManager) -> ExtensionManager.ExtensionIndex<*>,
val launchExtensionCreate: ((NavController) -> Unit)?,
) {
EXT_THEME(
id = "ext-theme",
titleResId = R.string.ext__list__ext_theme,
getExtensionIndex = { it.themes },
launchExtensionCreate = { it.navigate(Routes.Ext.Edit("null", ThemeExtension.SERIAL_TYPE)) },
),
EXT_KEYBOARD(
id = "ext-keyboard",
titleResId = R.string.ext__list__ext_keyboard,
getExtensionIndex = { it.keyboardExtensions },
launchExtensionCreate = null,//{ it.navigate(Routes.Ext.Edit("null", KeyboardExtension.SERIAL_TYPE)) },
),
EXT_LANGUAGEPACK(
id = "ext-languagepack",
titleResId = R.string.ext__list__ext_languagepack,
getExtensionIndex = { it.languagePacks },
launchExtensionCreate = null,//{ it.navigate(Routes.Ext.Edit("null", LanguagePackExtension.SERIAL_TYPE)) },
);
}
@Composable
fun ExtensionListScreen() = FlorisScreen {
title = stringRes(R.string.about__title)
fun ExtensionListScreen(type: ExtensionListScreenType, showUpdate: Boolean) = FlorisScreen {
title = stringRes(type.titleResId)
previewFieldVisible = false
/*val navController = LocalNavController.current
val context = LocalContext.current
val extensionManager = ExtensionManager.def
val navController = LocalNavController.current
val extensionManager by context.extensionManager()
val extensionIndex by type.getExtensionIndex(extensionManager).observeAsNonNullState()
Column(
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp, bottom = 32.dp)
) {
FlorisAppIcon()
Text(
text = stringRes(R.string.floris_app_name),
fontSize = 24.sp,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.padding(top = 16.dp),
)
}
Preference(
icon = R.drawable.ic_info,
title = stringRes(R.string.about__version__title),
summary = appVersion,
onClick = {
try {
val isImeSelected = InputMethodUtils.checkIsFlorisboardSelected(context)
if (isImeSelected) {
FlorisClipboardManager.getInstance().addNewPlaintext(appVersion)
} else {
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Florisboard version", appVersion)
clipboard.setPrimaryClip(clip)
content {
if (showUpdate) {
UpdateBox(extensionIndex = extensionIndex)
}
for (ext in extensionIndex) {
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
title = ext.meta.title,
subtitle = ext.meta.id,
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp),
text = ext.meta.description ?: "",
style = MaterialTheme.typography.bodySmall,
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.View(ext.meta.id))
},
icon = Icons.Outlined.Info,
text = stringRes(id = R.string.ext__list__view_details),//stringRes(R.string.action__add),
colors = ButtonDefaults.textButtonColors(),
)
Spacer(modifier = Modifier.weight(1f))
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.Edit(ext.meta.id))
},
icon = Icons.Default.Edit,
text = stringRes(R.string.action__edit),
enabled = extensionManager.canDelete(ext),
)
}
Toast.makeText(context, R.string.about__version_copied__title, Toast.LENGTH_SHORT).show()
} catch (e: Throwable) {
Toast.makeText(
context, context.getString(R.string.about__version_copied__error, e.message), Toast.LENGTH_SHORT
).show()
}
},
)
Preference(
icon = R.drawable.ic_history,
title = stringRes(R.string.about__changelog__title),
summary = stringRes(R.string.about__changelog__summary),
onClick = { launchUrl(context, R.string.florisboard__changelog_url, arrayOf(BuildConfig.VERSION_NAME)) },
)
Preference(
icon = R.drawable.ic_code,
title = stringRes(R.string.about__repository__title),
summary = stringRes(R.string.about__repository__summary),
onClick = { launchUrl(context, R.string.florisboard__repo_url) },
)
Preference(
icon = R.drawable.ic_policy,
title = stringRes(R.string.about__privacy_policy__title),
summary = stringRes(R.string.about__privacy_policy__summary),
onClick = { launchUrl(context, R.string.florisboard__privacy_policy_url) },
)
Preference(
icon = R.drawable.ic_description,
title = stringRes(R.string.about__project_license__title),
summary = stringRes(R.string.about__project_license__summary, "license_name" to "Apache 2.0"),
onClick = { navController.navigate(Routes.Settings.ProjectLicense) },
)
Preference(
icon = R.drawable.ic_description,
title = stringRes(id = R.string.about__third_party_licenses__title),
summary = stringRes(id = R.string.about__third_party_licenses__summary),
onClick = { navController.navigate(Routes.Settings.ThirdPartyLicenses) },
)*/
}
}
if (type.launchExtensionCreate != null) {
floatingActionButton {
ExtendedFloatingActionButton(
icon = {
Icon(
imageVector = Icons.Default.Add,
contentDescription = stringRes(id = R.string.ext__editor__title_create_any),
)
},
text = {
Text(
text = stringRes(id = R.string.ext__editor__title_create_any),
)
},
shape = FloatingActionButtonDefaults.extendedFabShape,
onClick = { type.launchExtensionCreate.invoke(navController) },
)
}
}
}

View File

@@ -18,10 +18,8 @@ package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Link
import androidx.compose.material.icons.filled.Mail
import androidx.compose.material.icons.outlined.Mail
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -32,13 +30,11 @@ 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.lib.android.launchUrl
import dev.patrickgold.florisboard.lib.compose.FlorisChip
import dev.patrickgold.florisboard.lib.ext.ExtensionMaintainer
import dev.patrickgold.florisboard.lib.util.launchUrl
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ExtensionMaintainerChip(
maintainer: ExtensionMaintainer,

View File

@@ -18,7 +18,7 @@ package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

View File

@@ -27,13 +27,13 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Divider
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Divider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -42,7 +42,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
@@ -52,7 +51,7 @@ import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.ime.nlp.LanguagePackExtension
import dev.patrickgold.florisboard.ime.theme.ThemeExtension
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentImpl
import dev.patrickgold.florisboard.lib.android.showLongToast
import org.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
@@ -150,7 +149,7 @@ private fun ViewScreen(ext: Extension) = FlorisScreen {
icon = Icons.Default.Delete,
text = stringRes(R.string.action__delete),
colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.error,
contentColor = MaterialTheme.colorScheme.error,
),
)
}

View File

@@ -1,27 +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.app.ext
import android.os.Bundle
import androidx.activity.ComponentActivity
class ImportFileActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val data = intent.data
}
}

View File

@@ -18,14 +18,13 @@ package dev.patrickgold.florisboard.app.settings
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Adb
import androidx.compose.material.icons.automirrored.outlined.Assignment
import androidx.compose.material.icons.filled.Extension
import androidx.compose.material.icons.filled.Gesture
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.LibraryBooks
import androidx.compose.material.icons.filled.SentimentSatisfiedAlt
import androidx.compose.material.icons.filled.SmartButton
import androidx.compose.material.icons.filled.Spellcheck
import androidx.compose.material.icons.outlined.Assignment
import androidx.compose.material.icons.outlined.Build
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Keyboard
@@ -131,18 +130,13 @@ fun HomeScreen() = FlorisScreen {
title = stringRes(R.string.settings__typing__title),
onClick = { navController.navigate(Routes.Settings.Typing) },
)
Preference(
icon = Icons.Default.LibraryBooks,
title = stringRes(R.string.settings__dictionary__title),
onClick = { navController.navigate(Routes.Settings.Dictionary) },
)
Preference(
icon = Icons.Default.Gesture,
title = stringRes(R.string.settings__gestures__title),
onClick = { navController.navigate(Routes.Settings.Gestures) },
)
Preference(
icon = Icons.Outlined.Assignment,
icon = Icons.AutoMirrored.Outlined.Assignment,
title = stringRes(R.string.settings__clipboard__title),
onClick = { navController.navigate(Routes.Settings.Clipboard) },
)
@@ -152,9 +146,9 @@ fun HomeScreen() = FlorisScreen {
onClick = { navController.navigate(Routes.Settings.Media) },
)
Preference(
icon = Icons.Default.Adb,
title = stringRes(R.string.devtools__title),
onClick = { navController.navigate(Routes.Devtools.Home) },
icon = Icons.Default.Extension,
title = stringRes(R.string.ext__home__title),
onClick = { navController.navigate(Routes.Ext.Home) },
)
Preference(
icon = Icons.Outlined.Build,

View File

@@ -22,13 +22,13 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.filled.History
import androidx.compose.material.icons.outlined.Description
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Policy
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -41,8 +41,8 @@ import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.lib.android.launchUrl
import dev.patrickgold.florisboard.lib.android.stringRes
import dev.patrickgold.florisboard.lib.util.launchUrl
import org.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

View File

@@ -18,7 +18,7 @@ package dev.patrickgold.florisboard.app.settings.about
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
@@ -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.assetManager
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
import dev.patrickgold.florisboard.lib.io.loadTextAsset
@Composable
fun ProjectLicenseScreen() = FlorisScreen {
@@ -41,7 +41,6 @@ fun ProjectLicenseScreen() = FlorisScreen {
scrollable = false
val context = LocalContext.current
val assetManager by context.assetManager()
content {
// Forcing LTR because the Apache 2.0 License shipped and displayed
@@ -54,8 +53,8 @@ fun ProjectLicenseScreen() = FlorisScreen {
.florisVerticalScroll()
.florisHorizontalScroll(),
) {
val licenseText = assetManager.loadTextAsset(
FlorisRef.assets("license/project_license.txt")
val licenseText = FlorisRef.assets("license/project_license.txt").loadTextAsset(
context
).getOrElse {
stringRes(R.string.about__project_license__error_license_text_failed, "error_message" to (it.message ?: ""))
}

View File

@@ -18,9 +18,11 @@ package dev.patrickgold.florisboard.app.settings.about
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import com.mikepenz.aboutlibraries.ui.compose.m3.LibraryDefaults
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
@@ -39,6 +41,13 @@ fun ThirdPartyLicensesScreen() = FlorisScreen {
modifier = Modifier
.fillMaxSize()
.florisScrollbar(lazyListState, isVertical = true),
colors = LibraryDefaults.libraryColors(
backgroundColor = MaterialTheme.colorScheme.background,
badgeBackgroundColor = MaterialTheme.colorScheme.primaryContainer,
badgeContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
contentColor = MaterialTheme.colorScheme.onBackground,
dialogConfirmButtonColor = MaterialTheme.colorScheme.primary,
),
lazyListState = lazyListState,
)
}

View File

@@ -17,7 +17,9 @@
package dev.patrickgold.florisboard.app.settings.advanced
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Adb
import androidx.compose.material.icons.filled.Archive
import androidx.compose.material.icons.filled.FormatPaint
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.Preview
@@ -28,10 +30,11 @@ import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.AppTheme
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
import dev.patrickgold.florisboard.lib.FlorisLocale
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import org.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
@@ -54,27 +57,14 @@ fun AdvancedScreen() = FlorisScreen {
prefs.advanced.settingsTheme,
icon = Icons.Default.Palette,
title = stringRes(R.string.pref__advanced__settings_theme__label),
entries = listPrefEntries {
entry(
key = AppTheme.AUTO,
label = stringRes(R.string.settings__system_default),
)
entry(
key = AppTheme.AUTO_AMOLED,
label = stringRes(R.string.pref__advanced__settings_theme__auto_amoled),
)
entry(
key = AppTheme.LIGHT,
label = stringRes(R.string.pref__advanced__settings_theme__light),
)
entry(
key = AppTheme.DARK,
label = stringRes(R.string.pref__advanced__settings_theme__dark),
)
entry(
key = AppTheme.AMOLED_DARK,
label = stringRes(R.string.pref__advanced__settings_theme__amoled_dark),
)
entries = enumDisplayEntriesOf(AppTheme::class),
)
SwitchPreference(
pref = prefs.advanced.useMaterialYou,
icon = Icons.Default.FormatPaint,
title = stringRes(R.string.pref__advanced__settings_material_you__label),
visibleIf = {
AndroidVersion.ATLEAST_API31_S
},
)
ListPreference(
@@ -155,7 +145,12 @@ fun AdvancedScreen() = FlorisScreen {
prefs.advanced.incognitoMode,
icon = vectorResource(id = R.drawable.ic_incognito),
title = stringRes(R.string.pref__advanced__incognito_mode__label),
entries = IncognitoMode.listEntries(),
entries = enumDisplayEntriesOf(IncognitoMode::class),
)
Preference(
icon = Icons.Default.Adb,
title = stringRes(R.string.devtools__title),
onClick = { navController.navigate(Routes.Devtools.Home) },
)
PreferenceGroup(title = stringRes(R.string.backup_and_restore__title)) {

View File

@@ -16,11 +16,15 @@
package dev.patrickgold.florisboard.app.settings.advanced
import android.content.ContentUris
import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material.Checkbox
import androidx.compose.material.RadioButton
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Checkbox
import androidx.compose.material3.RadioButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -28,14 +32,16 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.app.ShareCompat
import androidx.core.content.FileProvider
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.cacheManager
import dev.patrickgold.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.android.writeFromFile
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
import dev.patrickgold.florisboard.lib.cache.CacheManager
import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
@@ -47,17 +53,22 @@ import dev.patrickgold.florisboard.lib.devtools.flogError
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
import dev.patrickgold.florisboard.lib.io.FileRegistry
import dev.patrickgold.florisboard.lib.io.ZipUtils
import dev.patrickgold.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
import kotlinx.serialization.Serializable
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.android.writeFromFile
import org.florisboard.lib.kotlin.io.subDir
import org.florisboard.lib.kotlin.io.subFile
import org.florisboard.lib.kotlin.io.writeJson
object Backup {
const val FILE_PROVIDER_AUTHORITY = "${BuildConfig.APPLICATION_ID}.provider.file"
const val METADATA_JSON_NAME = "backup_metadata.json"
const val CLIPBOARD_TEXT_ITEMS_JSON_NAME = "clipboard_text_items.json"
const val CLIPBOARD_IMAGES_JSON_NAME = "clipboard_images.json"
const val CLIPBOARD_VIDEO_JSON_NAME = "clipboard_video.json"
fun defaultFileName(metadata: Metadata): String {
return "backup_${metadata.packageName}_${metadata.versionCode}_${metadata.timestamp}.zip"
@@ -72,9 +83,21 @@ object Backup {
var jetprefDatastore by mutableStateOf(true)
var imeKeyboard by mutableStateOf(true)
var imeTheme by mutableStateOf(true)
var clipboardTextItems by mutableStateOf(false)
var clipboardImageItems by mutableStateOf(false)
var clipboardVideoItems by mutableStateOf(false)
var clipboardData by mutableStateOf(false)
fun validateClipboardCheckbox(): Boolean {
return clipboardTextItems && clipboardImageItems && clipboardVideoItems
}
fun provideClipboardItems(): Boolean {
return clipboardTextItems || clipboardImageItems || clipboardVideoItems
}
fun atLeastOneSelected(): Boolean {
return jetprefDatastore || imeKeyboard || imeTheme
return jetprefDatastore || imeKeyboard || imeTheme || clipboardTextItems || clipboardImageItems || clipboardVideoItems
}
}
@@ -102,7 +125,7 @@ fun BackupScreen() = FlorisScreen {
var backupWorkspace: CacheManager.BackupAndRestoreWorkspace? = null
val backUpToFileSystemLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.CreateDocument(),
contract = ActivityResultContracts.CreateDocument("application/zip"),
onResult = { uri ->
if (uri == null) {
// User can modify checkboxes between cancellation and second
@@ -143,6 +166,36 @@ fun BackupScreen() = FlorisScreen {
dir.copyRecursively(workspaceFilesDir.subDir(ExtensionManager.IME_THEME_PATH))
}
}
if (backupFilesSelector.provideClipboardItems()) {
val clipboardHistory = context.clipboardManager().value.history().all
val clipboardFilesDir = workspace.inputDir.subDir("clipboard")
clipboardFilesDir.mkdir()
if (backupFilesSelector.clipboardTextItems) {
clipboardFilesDir.subFile(Backup.CLIPBOARD_TEXT_ITEMS_JSON_NAME)
.writeJson(clipboardHistory.filter { it.type == ItemType.TEXT })
}
if (backupFilesSelector.clipboardImageItems) {
clipboardFilesDir.subFile(Backup.CLIPBOARD_IMAGES_JSON_NAME)
.writeJson(clipboardHistory.filter { it.type == ItemType.IMAGE })
for (item in clipboardHistory.filter { it.type == ItemType.IMAGE }) {
val id = ContentUris.parseId(item.uri!!)
ClipboardFileStorage.getFileForId(context, id).copyTo(
clipboardFilesDir.subFile("${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/$id")
)
}
}
if (backupFilesSelector.clipboardVideoItems) {
clipboardFilesDir.subFile(Backup.CLIPBOARD_VIDEO_JSON_NAME)
.writeJson(clipboardHistory.filter { it.type == ItemType.VIDEO })
for (item in clipboardHistory.filter { it.type == ItemType.VIDEO }) {
val id = ContentUris.parseId(item.uri!!)
ClipboardFileStorage.getFileForId(context, id).copyTo(
clipboardFilesDir.subFile("${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/$id")
)
}
}
}
workspace.metadata = Backup.Metadata(
packageName = BuildConfig.APPLICATION_ID,
versionCode = BuildConfig.VERSION_CODE,
@@ -164,8 +217,10 @@ fun BackupScreen() = FlorisScreen {
Backup.Destination.FILE_SYS -> {
backUpToFileSystemLauncher.launch(backupWorkspace!!.zipFile.name)
}
Backup.Destination.SHARE_INTENT -> {
val uri = FileProvider.getUriForFile(context, Backup.FILE_PROVIDER_AUTHORITY, backupWorkspace!!.zipFile)
val uri =
FileProvider.getUriForFile(context, Backup.FILE_PROVIDER_AUTHORITY, backupWorkspace!!.zipFile)
val shareIntent = ShareCompat.IntentBuilder(context)
.setStream(uri)
.setType(FileRegistry.BackupArchive.mediaType)
@@ -253,6 +308,53 @@ internal fun BackupFilesSelector(
checked = filesSelector.imeTheme,
text = stringRes(R.string.backup_and_restore__back_up__files_ime_theme),
)
CheckboxListItem(
onClick = {
if (!filesSelector.clipboardData) {
filesSelector.clipboardTextItems = true
filesSelector.clipboardImageItems = true
filesSelector.clipboardVideoItems = true
} else {
filesSelector.clipboardTextItems = false
filesSelector.clipboardImageItems = false
filesSelector.clipboardVideoItems = false
}
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
},
checked = filesSelector.clipboardTextItems && filesSelector.clipboardImageItems && filesSelector.clipboardVideoItems,
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history)
)
CheckboxListItem(
onClick = {
filesSelector.clipboardTextItems = !filesSelector.clipboardTextItems
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
},
checked = filesSelector.clipboardTextItems,
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history__clipboard_text_items),
isSecondaryListItem = true,
)
CheckboxListItem(
onClick = {
filesSelector.clipboardImageItems = !filesSelector.clipboardImageItems
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
},
checked = filesSelector.clipboardImageItems,
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history__clipboard_image_items),
isSecondaryListItem = true,
)
CheckboxListItem(
onClick = {
filesSelector.clipboardVideoItems = !filesSelector.clipboardVideoItems
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
},
checked = filesSelector.clipboardVideoItems,
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history__clipboard_video_items),
isSecondaryListItem = true,
)
}
}
@@ -261,14 +363,20 @@ internal fun CheckboxListItem(
onClick: () -> Unit,
checked: Boolean,
text: String,
isSecondaryListItem: Boolean = false
) {
JetPrefListItem(
modifier = Modifier.rippleClickable(onClick = onClick),
icon = {
Checkbox(
checked = checked,
onCheckedChange = null,
)
Row {
if (isSecondaryListItem) {
Spacer(modifier = Modifier.width(40.dp))
}
Checkbox(
checked = checked,
onCheckedChange = null,
)
}
},
text = text,
)

View File

@@ -24,14 +24,13 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Code
import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -47,11 +46,13 @@ import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.cacheManager
import dev.patrickgold.florisboard.lib.android.readToFile
import dev.patrickgold.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
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.FlorisCardDefaults
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedButton
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -59,15 +60,17 @@ 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 org.florisboard.lib.android.readToFile
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
import org.florisboard.lib.kotlin.io.readJson
import org.florisboard.lib.kotlin.io.subDir
import org.florisboard.lib.kotlin.io.subFile
import java.io.FileNotFoundException
import java.text.DateFormat
import java.util.*
@@ -173,6 +176,48 @@ fun RestoreScreen() = FlorisScreen {
srcDir.copyRecursively(dstDir, overwrite = true)
}
}
if (restoreFilesSelector.provideClipboardItems()) {
val clipboardFilesDir = workspace.outputDir.subDir("clipboard")
val clipboardManager = context.clipboardManager().value
if (restoreFilesSelector.clipboardTextItems) {
val clipboardItems = clipboardFilesDir.subFile(Backup.CLIPBOARD_TEXT_ITEMS_JSON_NAME)
if (clipboardItems.exists()) {
val clipboardItemsList = clipboardItems.readJson<List<ClipboardItem>>()
clipboardManager.restoreHistory(shouldReset = shouldReset, items = clipboardItemsList.filter { it.type == ItemType.TEXT }, itemType = ItemType.TEXT)
}
}
if (restoreFilesSelector.clipboardImageItems) {
val clipboardItems = clipboardFilesDir.subFile(Backup.CLIPBOARD_IMAGES_JSON_NAME)
if (clipboardItems.exists()) {
val clipboardItemsList = clipboardItems.readJson<List<ClipboardItem>>()
for (item in clipboardItemsList.filter { it.type == ItemType.IMAGE }) {
ClipboardFileStorage.instertFileFromBackup(
context,
clipboardFilesDir.subFile(
relPath = "${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/${item.uri!!.path!!.split('/').last()}"
)
)
}
clipboardManager.restoreHistory(shouldReset = shouldReset, items = clipboardItemsList.filter { it.type == ItemType.IMAGE }, itemType = ItemType.IMAGE)
}
}
if (restoreFilesSelector.clipboardVideoItems) {
val clipboardItems = clipboardFilesDir.subFile(Backup.CLIPBOARD_VIDEO_JSON_NAME)
if (clipboardItems.exists()) {
val clipboardItemsList = clipboardItems.readJson<List<ClipboardItem>>()
for (item in clipboardItemsList.filter { it.type == ItemType.VIDEO }) {
ClipboardFileStorage.instertFileFromBackup(
context,
clipboardFilesDir.subFile(
relPath = "${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/${item.uri!!.path!!.split('/').last()}"
)
)
}
clipboardManager.restoreHistory(shouldReset = shouldReset, items = clipboardItemsList.filter { it.type == ItemType.VIDEO }, itemType = ItemType.VIDEO)
}
}
}
}
bottomBar {
@@ -181,7 +226,7 @@ fun RestoreScreen() = FlorisScreen {
ButtonBarTextButton(
onClick = {
restoreWorkspace?.close()
navController.popBackStack()
navController.navigateUp()
},
text = stringRes(R.string.action__cancel),
)
@@ -191,7 +236,7 @@ fun RestoreScreen() = FlorisScreen {
try {
performRestore()
context.showLongToast(R.string.backup_and_restore__restore__success)
navController.popBackStack()
navController.navigateUp()
} catch (e: Throwable) {
context.showLongToast(R.string.backup_and_restore__restore__failure, "error_message" to e.localizedMessage)
}
@@ -268,34 +313,34 @@ fun RestoreScreen() = FlorisScreen {
},
)
if (workspace.restoreErrorId != null) {
Column(modifier = Modifier.padding(CardDefaults.ContentPadding)) {
Column(modifier = Modifier.padding(FlorisCardDefaults.ContentPadding)) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(9.dp)
.padding(bottom = 8.dp)
.background(MaterialTheme.colors.error.copy(alpha = 0.56f))
.background(MaterialTheme.colorScheme.error.copy(alpha = 0.56f))
)
Text(
text = stringRes(workspace.restoreErrorId!!),
style = MaterialTheme.typography.body2,
color = MaterialTheme.colors.error,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error,
fontStyle = FontStyle.Italic,
)
}
} else if (workspace.restoreWarningId != null) {
Column(modifier = Modifier.padding(CardDefaults.ContentPadding)) {
Column(modifier = Modifier.padding(FlorisCardDefaults.ContentPadding)) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(9.dp)
.padding(bottom = 8.dp)
.background(LocalContentColor.current.copy(alpha = LocalContentAlpha.current))
.background(LocalContentColor.current)
)
Text(
text = stringRes(workspace.restoreWarningId!!),
style = MaterialTheme.typography.body2,
color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current,
fontStyle = FontStyle.Italic,
)
}

View File

@@ -23,16 +23,16 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -43,7 +43,6 @@ 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.res.painterResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
@@ -56,19 +55,19 @@ 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.florisboard.lib.util.launchActivity
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.android.stringRes
private val AllLanguagesLocale = FlorisLocale.from(language = "zz")
private val UserDictionaryEntryToAdd = UserDictionaryEntry(id = 0, "", 255, null, null)
@@ -214,14 +213,14 @@ fun UserDictionaryScreen(type: UserDictionaryType) = FlorisScreen {
importDictionary.launch("*/*")
expanded = false
},
content = { Text(text = stringRes(R.string.action__import)) },
text = { Text(text = stringRes(R.string.action__import)) },
)
DropdownMenuItem(
onClick = {
exportDictionary.launch("my-personal-dictionary.clb")
expanded = false
},
content = { Text(text = stringRes(R.string.action__export)) },
text = { Text(text = stringRes(R.string.action__export)) },
)
if (type == UserDictionaryType.SYSTEM) {
DropdownMenuItem(
@@ -229,7 +228,7 @@ fun UserDictionaryScreen(type: UserDictionaryType) = FlorisScreen {
context.launchActivity { it.action = SystemUserDictionaryUiIntentAction }
expanded = false
},
content = { Text(text = stringRes(R.string.settings__udm__open_system_manager_ui)) },
text = { Text(text = stringRes(R.string.settings__udm__open_system_manager_ui)) },
)
}
}

View File

@@ -21,6 +21,7 @@ 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.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.lib.compose.FlorisInfoCard
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -93,25 +94,25 @@ fun GesturesScreen() = FlorisScreen {
ListPreference(
prefs.gestures.swipeUp,
title = stringRes(R.string.pref__gestures__swipe_up__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
enabledIf = { prefs.glide.enabled isEqualTo false },
)
ListPreference(
prefs.gestures.swipeDown,
title = stringRes(R.string.pref__gestures__swipe_down__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
enabledIf = { prefs.glide.enabled isEqualTo false },
)
ListPreference(
prefs.gestures.swipeLeft,
title = stringRes(R.string.pref__gestures__swipe_left__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
enabledIf = { prefs.glide.enabled isEqualTo false },
)
ListPreference(
prefs.gestures.swipeRight,
title = stringRes(R.string.pref__gestures__swipe_right__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
enabledIf = { prefs.glide.enabled isEqualTo false },
)
}
@@ -120,22 +121,22 @@ fun GesturesScreen() = FlorisScreen {
ListPreference(
prefs.gestures.spaceBarSwipeUp,
title = stringRes(R.string.pref__gestures__space_bar_swipe_up__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
)
ListPreference(
prefs.gestures.spaceBarSwipeLeft,
title = stringRes(R.string.pref__gestures__space_bar_swipe_left__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
)
ListPreference(
prefs.gestures.spaceBarSwipeRight,
title = stringRes(R.string.pref__gestures__space_bar_swipe_right__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
)
ListPreference(
prefs.gestures.spaceBarLongPress,
title = stringRes(R.string.pref__gestures__space_bar_long_press__label),
entries = SwipeAction.generalListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "general"),
)
}
@@ -143,12 +144,12 @@ fun GesturesScreen() = FlorisScreen {
ListPreference(
prefs.gestures.deleteKeySwipeLeft,
title = stringRes(R.string.pref__gestures__delete_key_swipe_left__label),
entries = SwipeAction.deleteSwipeListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "deleteSwipe"),
)
ListPreference(
prefs.gestures.deleteKeyLongPress,
title = stringRes(R.string.pref__gestures__delete_key_long_press__label),
entries = SwipeAction.deleteLongPressListEntries(),
entries = enumDisplayEntriesOf(SwipeAction::class, "deleteLongPress"),
)
DialogSliderPreference(
prefs.gestures.swipeVelocityThreshold,

View File

@@ -19,11 +19,12 @@ package dev.patrickgold.florisboard.app.settings.keyboard
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.input.InputFeedbackActivationMode
import dev.patrickgold.florisboard.ime.input.HapticVibrationMode
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.android.systemVibratorOrNull
import dev.patrickgold.florisboard.lib.android.vibrate
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.systemVibratorOrNull
import org.florisboard.lib.android.vibrate
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
@@ -49,7 +50,7 @@ fun InputFeedbackScreen() = FlorisScreen {
switchPref = prefs.inputFeedback.audioEnabled,
title = stringRes(R.string.pref__input_feedback__audio_enabled__label),
summarySwitchDisabled = stringRes(R.string.pref__input_feedback__audio_enabled__summary_disabled),
entries = InputFeedbackActivationMode.audioListEntries(),
entries = enumDisplayEntriesOf(InputFeedbackActivationMode::class, "audio"),
)
DialogSliderPreference(
prefs.inputFeedback.audioVolume,
@@ -98,13 +99,13 @@ fun InputFeedbackScreen() = FlorisScreen {
switchPref = prefs.inputFeedback.hapticEnabled,
title = stringRes(R.string.pref__input_feedback__haptic_enabled__label),
summarySwitchDisabled = stringRes(R.string.pref__input_feedback__haptic_enabled__summary_disabled),
entries = InputFeedbackActivationMode.hapticListEntries(),
entries = enumDisplayEntriesOf(InputFeedbackActivationMode::class, "haptic")
)
ListPreference(
prefs.inputFeedback.hapticVibrationMode,
title = stringRes(R.string.pref__input_feedback__haptic_vibration_mode__label),
enabledIf = { prefs.inputFeedback.hapticEnabled isEqualTo true },
entries = HapticVibrationMode.listEntries(),
entries = enumDisplayEntriesOf(HapticVibrationMode::class),
)
DialogSliderPreference(
prefs.inputFeedback.hapticVibrationDuration,

View File

@@ -20,10 +20,12 @@ import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.input.CapitalizationBehavior
import dev.patrickgold.florisboard.ime.keyboard.SpaceBarMode
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
import dev.patrickgold.florisboard.ime.smartbar.IncognitoDisplayMode
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -54,14 +56,14 @@ fun KeyboardScreen() = FlorisScreen {
switchPref = prefs.keyboard.hintedNumberRowEnabled,
title = stringRes(R.string.pref__keyboard__hinted_number_row_mode__label),
summarySwitchDisabled = stringRes(R.string.state__disabled),
entries = KeyHintMode.listEntries(),
entries = enumDisplayEntriesOf(KeyHintMode::class),
)
ListPreference(
listPref = prefs.keyboard.hintedSymbolsMode,
switchPref = prefs.keyboard.hintedSymbolsEnabled,
title = stringRes(R.string.pref__keyboard__hinted_symbols_mode__label),
summarySwitchDisabled = stringRes(R.string.state__disabled),
entries = KeyHintMode.listEntries(),
entries = enumDisplayEntriesOf(KeyHintMode::class),
)
SwitchPreference(
prefs.keyboard.utilityKeyEnabled,
@@ -71,18 +73,18 @@ fun KeyboardScreen() = FlorisScreen {
ListPreference(
prefs.keyboard.utilityKeyAction,
title = stringRes(R.string.pref__keyboard__utility_key_action__label),
entries = UtilityKeyAction.listEntries(),
entries = enumDisplayEntriesOf(UtilityKeyAction::class),
visibleIf = { prefs.keyboard.utilityKeyEnabled isEqualTo true },
)
ListPreference(
prefs.keyboard.spaceBarMode,
title = stringRes(R.string.pref__keyboard__space_bar_mode__label),
entries = SpaceBarMode.listEntries(),
entries = enumDisplayEntriesOf(SpaceBarMode::class),
)
ListPreference(
prefs.keyboard.capitalizationBehavior,
title = stringRes(R.string.pref__keyboard__capitalization_behavior__label),
entries = CapitalizationBehavior.listEntries(),
entries = enumDisplayEntriesOf(CapitalizationBehavior::class),
)
DialogSliderPreference(
primaryPref = prefs.keyboard.fontSizeMultiplierPortrait,
@@ -95,12 +97,17 @@ fun KeyboardScreen() = FlorisScreen {
max = 150,
stepIncrement = 5,
)
ListPreference(
listPref = prefs.keyboard.incognitoDisplayMode,
title = stringRes(R.string.pref__keyboard__incognito_indicator__label),
entries = enumDisplayEntriesOf(IncognitoDisplayMode::class),
)
PreferenceGroup(title = stringRes(R.string.pref__keyboard__group_layout__label)) {
ListPreference(
prefs.keyboard.oneHandedMode,
title = stringRes(R.string.pref__keyboard__one_handed_mode__label),
entries = OneHandedMode.listEntries(),
entries = enumDisplayEntriesOf(OneHandedMode::class),
)
DialogSliderPreference(
prefs.keyboard.oneHandedModeScaleFactor,
@@ -114,7 +121,7 @@ fun KeyboardScreen() = FlorisScreen {
ListPreference(
prefs.keyboard.landscapeInputUiMode,
title = stringRes(R.string.pref__keyboard__landscape_input_ui_mode__label),
entries = LandscapeInputUiMode.listEntries(),
entries = enumDisplayEntriesOf(LandscapeInputUiMode::class),
)
DialogSliderPreference(
primaryPref = prefs.keyboard.heightFactorPortrait,

View File

@@ -25,12 +25,12 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Input
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
@@ -47,7 +47,7 @@ import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.ime.nlp.LanguagePackComponent
import dev.patrickgold.florisboard.lib.android.showLongToast
import org.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.compose.FlorisConfirmDeleteDialog
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -177,7 +177,7 @@ fun LanguagePackManagerScreen(action: LanguagePackManagerScreenAction?) = Floris
icon = Icons.Default.Delete,
text = stringRes(R.string.action__delete),
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colors.error,
contentColor = MaterialTheme.colorScheme.error,
),
)
Spacer(modifier = Modifier.weight(1f))

View File

@@ -17,11 +17,12 @@
package dev.patrickgold.florisboard.app.settings.localization
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -31,6 +32,7 @@ import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.cacheManager
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
import dev.patrickgold.florisboard.ime.keyboard.LayoutType
@@ -70,16 +72,16 @@ fun LocalizationScreen() = FlorisScreen {
text = stringRes(R.string.settings__localization__subtype_add_title),
)
},
shape = FloatingActionButtonDefaults.extendedFabShape,
onClick = { navController.navigate(Routes.Settings.SubtypeAdd) },
)
}
content {
ListPreference(
prefs.localization.displayLanguageNamesIn,
title = stringRes(R.string.settings__localization__display_language_names_in__label),
entries = DisplayLanguageNamesIn.listEntries(),
entries = enumDisplayEntriesOf(DisplayLanguageNamesIn::class),
)
Preference(
// icon = R.drawable.ic_edit,

View File

@@ -24,13 +24,13 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -41,7 +41,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
@@ -107,7 +106,7 @@ fun SelectLocaleScreen() = FlorisScreen {
},
singleLine = true,
shape = RectangleShape,
colors = TextFieldDefaults.textFieldColors(
colors = TextFieldDefaults.colors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,

View File

@@ -25,14 +25,14 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Button
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.MutableState
@@ -48,7 +48,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -66,7 +65,6 @@ import dev.patrickgold.florisboard.ime.core.SubtypePreset
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.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.nlp.han.HanShapeBasedLanguageProvider
import dev.patrickgold.florisboard.ime.nlp.latin.LatinLanguageProvider
import dev.patrickgold.florisboard.keyboardManager
@@ -82,7 +80,6 @@ import dev.patrickgold.florisboard.subtypeManager
import dev.patrickgold.jetpref.datastore.model.observeAsState
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
private val SelectComponentName = ExtensionComponentName("00", "00")
@@ -281,7 +278,7 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
Text(
modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp),
text = stringRes(R.string.settings__localization__suggested_subtype_presets),
color = MaterialTheme.colors.primary,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -388,7 +385,7 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
)
val nlpProviderMappingIds = remember(nlpProviderMappings) {
SelectListKeys + nlpProviderMappings.keys
listOf(SelectNlpProviderId) + nlpProviderMappings.keys
}
val nlpProviderMappingLabels = remember(nlpProviderMappings) {
selectListValues + nlpProviderMappings.values.map { it }
@@ -401,8 +398,8 @@ fun SubtypeEditorScreen(id: Long?) = FlorisScreen {
selectedIndex = selectedIndex,
isError = showSelectAsError && selectedIndex == 0,
onSelectItem = { nlpProviders = SubtypeNlpProviderMap(
suggestion = nlpProviderMappingIds[it] as String,
spelling = nlpProviderMappingIds[it] as String
suggestion = nlpProviderMappingIds[it],
spelling = nlpProviderMappingIds[it]
) },
onExpandRequest = { expanded = true },
onDismissRequest = { expanded = false },
@@ -583,7 +580,7 @@ private fun SubtypeProperty(text: String, content: @Composable () -> Unit) {
Text(
modifier = Modifier.padding(bottom = 8.dp),
text = text,
style = MaterialTheme.typography.subtitle2,
style = MaterialTheme.typography.titleSmall,
)
content()
}

View File

@@ -18,6 +18,7 @@ package dev.patrickgold.florisboard.app.settings.media
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.pluralsRes
@@ -37,7 +38,7 @@ fun MediaScreen() = FlorisScreen {
ListPreference(
prefs.media.emojiPreferredSkinTone,
title = stringRes(R.string.prefs__media__emoji_preferred_skin_tone),
entries = EmojiSkinTone.listEntries(),
entries = enumDisplayEntriesOf(EmojiSkinTone::class),
)
DialogSliderPreference(
prefs.media.emojiRecentlyUsedMaxSize,

View File

@@ -18,6 +18,7 @@ package dev.patrickgold.florisboard.app.settings.smartbar
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.smartbar.CandidatesDisplayMode
import dev.patrickgold.florisboard.ime.smartbar.ExtendedActionsPlacement
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
@@ -41,7 +42,7 @@ fun SmartbarScreen() = FlorisScreen {
ListPreference(
listPref = prefs.smartbar.layout,
title = stringRes(R.string.pref__smartbar__layout__label),
entries = SmartbarLayout.listEntries(),
entries = enumDisplayEntriesOf(SmartbarLayout::class),
enabledIf = { prefs.smartbar.enabled isEqualTo true },
)
@@ -49,7 +50,7 @@ fun SmartbarScreen() = FlorisScreen {
ListPreference(
prefs.suggestion.displayMode,
title = stringRes(R.string.pref__suggestion__display_mode__label),
entries = CandidatesDisplayMode.listEntries(),
entries = enumDisplayEntriesOf(CandidatesDisplayMode::class),
enabledIf = { prefs.smartbar.enabled isEqualTo true },
visibleIf = { prefs.smartbar.layout isNotEqualTo SmartbarLayout.ACTIONS_ONLY },
)
@@ -73,7 +74,7 @@ fun SmartbarScreen() = FlorisScreen {
ListPreference(
listPref = prefs.smartbar.extendedActionsPlacement,
title = stringRes(R.string.pref__smartbar__extended_actions_placement__label),
entries = ExtendedActionsPlacement.listEntries(),
entries = enumDisplayEntriesOf(ExtendedActionsPlacement::class),
enabledIf = { prefs.smartbar.enabled isEqualTo true },
visibleIf = { prefs.smartbar.layout isEqualTo SmartbarLayout.SUGGESTIONS_ACTIONS_EXTENDED },
)

View File

@@ -16,34 +16,10 @@
package dev.patrickgold.florisboard.app.settings.theme
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
import org.florisboard.lib.kotlin.curlyFormat
/**
* DisplayColorsAs indicates how color strings should be visually presented to the user.
*/
enum class DisplayColorsAs {
HEX8,
RGBA;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = HEX8,
label = stringRes(R.string.enum__display_colors_as__hex8),
description = stringRes(R.string.general__example_given).curlyFormat("example" to "#4caf50ff"),
showDescriptionOnlyIfSelected = true,
)
entry(
key = RGBA,
label = stringRes(R.string.enum__display_colors_as__rgba),
description = stringRes(R.string.general__example_given).curlyFormat("example" to "rgba(76,175,80,1.0)"),
showDescriptionOnlyIfSelected = true,
)
}
}
}

View File

@@ -16,11 +16,6 @@
package dev.patrickgold.florisboard.app.settings.theme
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
/**
* DisplayPreviewAfterDialogs indicates if the keyboard should auto-open after closing
* any dialog. This is useful because the dialog always hides the keyboard and one may
@@ -30,28 +25,4 @@ enum class DisplayKbdAfterDialogs {
ALWAYS,
NEVER,
REMEMBER;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = ALWAYS,
label = stringRes(R.string.enum__display_kbd_after_dialogs__always),
description = stringRes(R.string.enum__display_kbd_after_dialogs__always__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = NEVER,
label = stringRes(R.string.enum__display_kbd_after_dialogs__never),
description = stringRes(R.string.enum__display_kbd_after_dialogs__never__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = REMEMBER,
label = stringRes(R.string.enum__display_kbd_after_dialogs__remember),
description = stringRes(R.string.enum__display_kbd_after_dialogs__remember__description),
showDescriptionOnlyIfSelected = true,
)
}
}
}

View File

@@ -30,12 +30,11 @@ import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.HelpOutline
import androidx.compose.material.icons.outlined.HelpOutline
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
@@ -49,7 +48,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@@ -72,29 +70,29 @@ import dev.patrickgold.florisboard.lib.compose.rippleClickable
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.ExtensionValidation
import dev.patrickgold.florisboard.lib.rememberValidationResult
import dev.patrickgold.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.snygg.SnyggPropertySetSpec
import dev.patrickgold.florisboard.lib.snygg.value.MaterialYouColor
import dev.patrickgold.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggCutCornerPercentShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDefinedVarValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDpSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggImplicitInheritValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouDarkColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggPercentShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggRoundedCornerPercentShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggSolidColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggSpSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggValueEncoder
import dev.patrickgold.florisboard.lib.snygg.value.SnyggVarValueEncoders
import org.florisboard.lib.snygg.SnyggLevel
import org.florisboard.lib.snygg.SnyggPropertySetSpec
import org.florisboard.lib.snygg.value.MaterialYouColor
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
import org.florisboard.lib.snygg.value.SnyggCutCornerPercentShapeValue
import org.florisboard.lib.snygg.value.SnyggDefinedVarValue
import org.florisboard.lib.snygg.value.SnyggDpShapeValue
import org.florisboard.lib.snygg.value.SnyggDpSizeValue
import org.florisboard.lib.snygg.value.SnyggImplicitInheritValue
import org.florisboard.lib.snygg.value.SnyggMaterialYouDarkColorValue
import org.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
import org.florisboard.lib.snygg.value.SnyggMaterialYouValue
import org.florisboard.lib.snygg.value.SnyggPercentShapeValue
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
import org.florisboard.lib.snygg.value.SnyggRoundedCornerPercentShapeValue
import org.florisboard.lib.snygg.value.SnyggShapeValue
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
import org.florisboard.lib.snygg.value.SnyggSpSizeValue
import org.florisboard.lib.snygg.value.SnyggValue
import org.florisboard.lib.snygg.value.SnyggValueEncoder
import org.florisboard.lib.snygg.value.SnyggVarValueEncoders
import dev.patrickgold.florisboard.lib.stripUnicodeCtrlChars
import dev.patrickgold.jetpref.material.ui.ExperimentalJetPrefMaterialUi
import dev.patrickgold.jetpref.material.ui.ExperimentalJetPrefMaterial3Ui
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import dev.patrickgold.jetpref.material.ui.JetPrefColorPicker
import dev.patrickgold.jetpref.material.ui.rememberJetPrefColorPickerState
@@ -220,7 +218,7 @@ internal fun EditPropertyDialog(
},
onNeutral = onDelete,
neutralColors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colors.error,
contentColor = MaterialTheme.colorScheme.error,
),
) {
Column {
@@ -228,7 +226,7 @@ internal fun EditPropertyDialog(
Text(
modifier = Modifier.padding(bottom = 16.dp),
text = stringRes(R.string.settings__theme_editor__property_already_exists),
color = MaterialTheme.colors.error,
color = MaterialTheme.colorScheme.error,
)
}
@@ -353,7 +351,7 @@ private fun PropertyValueEncoderDropdown(
)
}
@OptIn(ExperimentalJetPrefMaterialUi::class)
@OptIn(ExperimentalJetPrefMaterial3Ui::class)
@Composable
private fun PropertyValueEditor(
value: SnyggValue,
@@ -417,7 +415,7 @@ private fun PropertyValueEditor(
.padding(end = 12.dp)
.weight(1f),
text = colorPickerStr,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
fontFamily = FontFamily.Monospace,
)
SnyggValueIcon(
@@ -477,7 +475,7 @@ private fun PropertyValueEditor(
rgb(r,g,b)
-> r,g,b in 0..255
""".trimIndent(),
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
fontFamily = FontFamily.Monospace,
)
}
@@ -680,7 +678,7 @@ private fun PropertyValueEditor(
Box(
modifier = Modifier
.requiredSize(40.dp)
.border(1.dp, MaterialTheme.colors.onBackground, shape),
.border(1.dp, MaterialTheme.colorScheme.onBackground, shape),
)
Column {
FlorisChip(
@@ -849,7 +847,7 @@ private fun PropertyValueEditor(
Box(
modifier = Modifier
.requiredSize(40.dp)
.border(1.dp, MaterialTheme.colors.onBackground, shape),
.border(1.dp, MaterialTheme.colorScheme.onBackground, shape),
)
Column {
FlorisChip(
@@ -938,7 +936,7 @@ private fun PropertyValueEditor(
Box(
modifier = Modifier
.requiredSize(40.dp)
.border(1.dp, MaterialTheme.colors.onBackground, value.shape),
.border(1.dp, MaterialTheme.colorScheme.onBackground, value.shape),
)
}
}

View File

@@ -39,16 +39,17 @@ import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.HelpOutline
import androidx.compose.material.icons.filled.Pageview
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
@@ -65,7 +66,6 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -85,8 +85,8 @@ import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.ime.theme.FlorisImeUiSpec
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.NATIVE_NULLPTR
import dev.patrickgold.florisboard.lib.android.showShortToast
import dev.patrickgold.florisboard.lib.android.stringRes
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.stringRes
import dev.patrickgold.florisboard.lib.compose.FlorisChip
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownMenu
import dev.patrickgold.florisboard.lib.compose.FlorisHyperlinkText
@@ -94,8 +94,8 @@ import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedTextField
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.snygg.SnyggRule
import org.florisboard.lib.snygg.SnyggLevel
import org.florisboard.lib.snygg.SnyggRule
import dev.patrickgold.florisboard.lib.util.InputMethodUtils
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import org.florisboard.lib.kotlin.curlyFormat
@@ -190,7 +190,7 @@ internal fun EditRuleDialog(
} else {
null
},
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error),
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error),
onNeutral = { onDeleteRule(initRule) },
) {
Column {
@@ -198,7 +198,7 @@ internal fun EditRuleDialog(
Text(
modifier = Modifier.padding(bottom = 16.dp),
text = stringRes(R.string.settings__theme_editor__rule_already_exists),
color = MaterialTheme.colors.error,
color = MaterialTheme.colorScheme.error,
)
}
@@ -224,7 +224,8 @@ internal fun EditRuleDialog(
SnyggLevel.DEVELOPER -> SnyggRule.PRESSED_SELECTOR
else -> stringRes(R.string.snygg__rule_selector__pressed)
},
color = if (pressedSelector) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = pressedSelector,
color = if (pressedSelector) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
FlorisChip(
onClick = { focusSelector = !focusSelector },
@@ -233,7 +234,8 @@ internal fun EditRuleDialog(
SnyggLevel.DEVELOPER -> SnyggRule.FOCUS_SELECTOR
else -> stringRes(R.string.snygg__rule_selector__focus)
},
color = if (focusSelector) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = focusSelector,
color = if (focusSelector) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
FlorisChip(
onClick = { disabledSelector = !disabledSelector },
@@ -241,7 +243,8 @@ internal fun EditRuleDialog(
SnyggLevel.DEVELOPER -> SnyggRule.DISABLED_SELECTOR
else -> stringRes(R.string.snygg__rule_selector__disabled)
},
color = if (disabledSelector) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = disabledSelector,
color = if (disabledSelector) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
}
}
@@ -270,6 +273,7 @@ internal fun EditRuleDialog(
FlorisChip(
onClick = { editCodeDialogValue = code },
text = code.toString(),
selected = editCodeDialogValue == code,
shape = MaterialTheme.shapes.medium,
)
}
@@ -286,7 +290,8 @@ internal fun EditRuleDialog(
}
else -> stringRes(R.string.enum__input_shift_state__unshifted)
},
color = if (shiftStateUnshifted) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = shiftStateUnshifted,
color = if (shiftStateUnshifted) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
FlorisChip(
onClick = { shiftStateShiftedManual = !shiftStateShiftedManual },
@@ -296,7 +301,8 @@ internal fun EditRuleDialog(
}
else -> stringRes(R.string.enum__input_shift_state__shifted_manual)
},
color = if (shiftStateShiftedManual) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = shiftStateShiftedManual,
color = if (shiftStateShiftedManual) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
FlorisChip(
onClick = { shiftStateShiftedAutomatic = !shiftStateShiftedAutomatic },
@@ -306,7 +312,8 @@ internal fun EditRuleDialog(
}
else -> stringRes(R.string.enum__input_shift_state__shifted_automatic)
},
color = if (shiftStateShiftedAutomatic) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = shiftStateShiftedAutomatic,
color = if (shiftStateShiftedAutomatic) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
FlorisChip(
onClick = { shiftStateCapsLock = !shiftStateCapsLock },
@@ -316,7 +323,8 @@ internal fun EditRuleDialog(
}
else -> stringRes(R.string.enum__input_shift_state__caps_lock)
},
color = if (shiftStateCapsLock) MaterialTheme.colors.primaryVariant else Color.Unspecified,
selected = shiftStateCapsLock,
color = if (shiftStateCapsLock) MaterialTheme.colorScheme.secondary else Color.Unspecified,
)
}
}
@@ -335,6 +343,7 @@ internal fun EditRuleDialog(
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun EditCodeValueDialog(
codeValue: Int,
@@ -368,7 +377,7 @@ private fun EditCodeValueDialog(
val recordingKeyColor = if (isRecordingKey) {
rememberInfiniteTransition().animateColor(
initialValue = LocalContentColor.current,
targetValue = MaterialTheme.colors.error,
targetValue = MaterialTheme.colorScheme.error,
animationSpec = infiniteRepeatable(
tween(750),
repeatMode = RepeatMode.Reverse,
@@ -461,7 +470,7 @@ private fun EditCodeValueDialog(
} else {
null
},
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error),
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error),
onNeutral = {
onDelete(codeValue)
onDismiss()
@@ -526,12 +535,12 @@ private fun EditCodeValueDialog(
isError = showError,
singleLine = true,
colors = if (isRecordingKey) {
TextFieldDefaults.outlinedTextFieldColors(
textColor = Color.Transparent,
OutlinedTextFieldDefaults.colors(
focusedTextColor = Color.Transparent,
cursorColor = Color.Transparent,
)
} else {
TextFieldDefaults.outlinedTextFieldColors()
OutlinedTextFieldDefaults.colors()
},
)
}
@@ -550,7 +559,7 @@ private fun EditCodeValueDialog(
"i_min" to KeyCode.Spec.INTERNAL_MIN,
"i_max" to KeyCode.Spec.INTERNAL_MAX,
),
color = MaterialTheme.colors.error,
color = MaterialTheme.colorScheme.error,
)
}
}
@@ -593,7 +602,7 @@ private fun TextKeyDataPreviewBox(
modifier = Modifier
.padding(end = 16.dp)
.background(
color = MaterialTheme.colors.onSurface.copy(alpha = 0.12f),
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
shape = MaterialTheme.shapes.medium,
)
.height(36.dp)

View File

@@ -20,9 +20,10 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.snygg.SnyggLevel
import org.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.PreferenceLayout
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
@@ -40,17 +41,17 @@ fun FineTuneDialog(onDismiss: () -> Unit) {
ListPreference(
listPref = prefs.theme.editorLevel,
title = stringRes(R.string.settings__theme_editor__fine_tune__level),
entries = SnyggLevel.listEntries(),
entries = enumDisplayEntriesOf(SnyggLevel::class),
)
ListPreference(
listPref = prefs.theme.editorDisplayColorsAs,
title = stringRes(R.string.settings__theme_editor__fine_tune__display_colors_as),
entries = DisplayColorsAs.listEntries(),
entries = enumDisplayEntriesOf(DisplayColorsAs::class),
)
ListPreference(
listPref = prefs.theme.editorDisplayKbdAfterDialogs,
title = stringRes(R.string.settings__theme_editor__fine_tune__display_kbd_after_dialogs),
entries = DisplayKbdAfterDialogs.listEntries(),
entries = enumDisplayEntriesOf(DisplayKbdAfterDialogs::class),
)
}
}

View File

@@ -25,32 +25,29 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.FormatSize
import androidx.compose.material.icons.filled.Link
import androidx.compose.material.icons.filled.Straighten
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDefinedVarValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDpSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggSolidColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggSpSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggValue
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
import org.florisboard.lib.snygg.value.SnyggDefinedVarValue
import org.florisboard.lib.snygg.value.SnyggDpSizeValue
import org.florisboard.lib.snygg.value.SnyggMaterialYouValue
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
import org.florisboard.lib.snygg.value.SnyggShapeValue
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
import org.florisboard.lib.snygg.value.SnyggSpSizeValue
import org.florisboard.lib.snygg.value.SnyggValue
import dev.patrickgold.jetpref.material.ui.checkeredBackground
object SnyggValueIcon {
@@ -102,7 +99,7 @@ internal fun SnyggValueIcon(
Box(
modifier = modifier
.requiredSize(spec.iconSizeMinusBorder)
.border(spec.borderWith, MaterialTheme.colors.onBackground, value.alwaysPercentShape())
.border(spec.borderWith, MaterialTheme.colorScheme.onBackground, value.alwaysPercentShape())
)
}
is SnyggDpSizeValue -> {
@@ -143,7 +140,7 @@ internal fun SnyggValueIcon(
.offset(x = 1.dp)
.requiredSize(smallSpec.iconSize)
.padding(vertical = 2.dp)
.background(MaterialTheme.colors.background, spec.boxShape),
.background(MaterialTheme.colorScheme.background, spec.boxShape),
)
Icon(
modifier = Modifier.requiredSize(smallSpec.iconSize),
@@ -167,8 +164,8 @@ internal fun SnyggValueColorBox(
) {
Surface(
modifier = modifier.requiredSize(spec.iconSize),
color = MaterialTheme.colors.background,
elevation = spec.elevation,
color = MaterialTheme.colorScheme.background,
shadowElevation = spec.elevation,
shape = spec.boxShape,
) {
Box(

View File

@@ -33,18 +33,18 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
@@ -62,13 +62,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.apptheme.Shapes
import dev.patrickgold.florisboard.app.ext.ExtensionComponentView
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.ime.theme.FlorisImeUiSpec
@@ -76,7 +76,6 @@ import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentEditor
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionEditor
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.cache.CacheManager
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
@@ -89,24 +88,25 @@ import dev.patrickgold.florisboard.lib.compose.rememberPreviewFieldController
import dev.patrickgold.florisboard.lib.compose.rippleClickable
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.ExtensionValidation
import dev.patrickgold.florisboard.lib.io.readJson
import dev.patrickgold.florisboard.lib.io.subFile
import dev.patrickgold.florisboard.lib.rememberValidationResult
import dev.patrickgold.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.snygg.SnyggPropertySetEditor
import dev.patrickgold.florisboard.lib.snygg.SnyggPropertySetSpec
import dev.patrickgold.florisboard.lib.snygg.SnyggRule
import dev.patrickgold.florisboard.lib.snygg.SnyggStylesheet
import dev.patrickgold.florisboard.lib.snygg.SnyggStylesheetEditor
import dev.patrickgold.florisboard.lib.snygg.SnyggStylesheetJsonConfig
import dev.patrickgold.florisboard.lib.snygg.definedVariablesRule
import dev.patrickgold.florisboard.lib.snygg.isDefinedVariablesRule
import dev.patrickgold.florisboard.themeManager
import dev.patrickgold.jetpref.datastore.model.observeAsState
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.kotlin.io.readJson
import org.florisboard.lib.kotlin.io.subFile
import org.florisboard.lib.snygg.SnyggLevel
import org.florisboard.lib.snygg.SnyggPropertySetEditor
import org.florisboard.lib.snygg.SnyggPropertySetSpec
import org.florisboard.lib.snygg.SnyggRule
import org.florisboard.lib.snygg.SnyggStylesheet
import org.florisboard.lib.snygg.SnyggStylesheetEditor
import org.florisboard.lib.snygg.SnyggStylesheetJsonConfig
import org.florisboard.lib.snygg.definedVariablesRule
import org.florisboard.lib.snygg.isDefinedVariablesRule
internal val IntListSaver = Saver<SnapshotStateList<Int>, ArrayList<Int>>(
save = { ArrayList(it) },
@@ -300,7 +300,7 @@ fun ThemeEditorScreen(
Text(
modifier = Modifier.padding(bottom = 8.dp, start = 16.dp, end = 16.dp),
text = stringRes(R.string.snygg__rule_element__defines_description),
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
fontStyle = FontStyle.Italic,
)
}
@@ -549,9 +549,9 @@ private fun SnyggRuleRow(
Text(
modifier = Modifier
.padding(end = 8.dp)
.background(MaterialTheme.colors.primaryVariant),
.background(MaterialTheme.colorScheme.primaryContainer, shape = Shapes.small),
text = text,
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
fontFamily = FontFamily.Monospace,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -562,7 +562,7 @@ private fun SnyggRuleRow(
fun AttributesList(text: String, list: String) {
Text(
text = "$text = $list",
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
color = LocalContentColor.current.copy(alpha = 0.56f),
fontFamily = FontFamily.Monospace,
maxLines = 1,
@@ -582,7 +582,7 @@ private fun SnyggRuleRow(
) {
Text(
text = translateElementName(rule, level),
style = MaterialTheme.typography.body2,
style = MaterialTheme.typography.bodyMedium,
fontFamily = FontFamily.Monospace,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -618,14 +618,14 @@ private fun SnyggRuleRow(
FlorisIconButton(
onClick = onEditRuleBtnClick,
icon = Icons.Default.Edit,
iconColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colorScheme.primary,
iconModifier = Modifier.size(ButtonDefaults.IconSize),
)
}
FlorisIconButton(
onClick = onAddPropertyBtnClick,
icon = Icons.Default.Add,
iconColor = MaterialTheme.colors.secondary,
iconColor = MaterialTheme.colorScheme.secondary,
iconModifier = Modifier.size(ButtonDefaults.IconSize),
)
}
@@ -645,7 +645,7 @@ internal fun DialogProperty(
.weight(1f)
.padding(vertical = 8.dp),
text = text,
style = MaterialTheme.typography.subtitle2,
style = MaterialTheme.typography.titleSmall,
)
trailingIconTitle()
}

View File

@@ -16,83 +16,56 @@
package dev.patrickgold.florisboard.app.settings.theme
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.RadioButton
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Input
import androidx.compose.material.icons.filled.LightMode
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.RadioButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.ext.ExtensionImportScreenType
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.ime.theme.ThemeExtension
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
import dev.patrickgold.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.compose.FlorisConfirmDeleteDialog
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.rippleClickable
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.Extension
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
import dev.patrickgold.florisboard.lib.observeAsNonNullState
import dev.patrickgold.florisboard.themeManager
import dev.patrickgold.jetpref.datastore.model.observeAsState
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
enum class ThemeManagerScreenAction(val id: String) {
SELECT_DAY("select-day"),
SELECT_NIGHT("select-night"),
MANAGE("manage-installed-themes");
SELECT_NIGHT("select-night");
}
@OptIn(ExperimentalJetPrefDatastoreUi::class)
@Composable
fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
title = stringRes(when (action) {
ThemeManagerScreenAction.SELECT_DAY -> R.string.settings__theme_manager__title_day
ThemeManagerScreenAction.SELECT_NIGHT -> R.string.settings__theme_manager__title_night
ThemeManagerScreenAction.MANAGE -> R.string.settings__theme_manager__title_manage
else -> error("Theme manager screen action must not be null")
})
previewFieldVisible = action != ThemeManagerScreenAction.MANAGE
previewFieldVisible = true
val prefs by florisPreferenceModel()
val navController = LocalNavController.current
val context = LocalContext.current
val extensionManager by context.extensionManager()
val themeManager by context.themeManager()
val indexedThemeExtensions by extensionManager.themes.observeAsNonNullState()
val selectedManagerThemeId = remember { mutableStateOf<ExtensionComponentName?>(null) }
val extGroupedThemes = remember(indexedThemeExtensions) {
buildMap<String, List<ThemeExtensionComponent>> {
for (ext in indexedThemeExtensions) {
@@ -104,7 +77,6 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
fun getThemeIdPref() = when (action) {
ThemeManagerScreenAction.SELECT_DAY -> prefs.theme.dayThemeId
ThemeManagerScreenAction.SELECT_NIGHT -> prefs.theme.nightThemeId
ThemeManagerScreenAction.MANAGE -> error("internal error in manager logic")
}
fun setTheme(extId: String, componentId: String) {
@@ -114,18 +86,13 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
ThemeManagerScreenAction.SELECT_NIGHT -> {
getThemeIdPref().set(extComponentName)
}
ThemeManagerScreenAction.MANAGE -> {
selectedManagerThemeId.value = extComponentName
}
}
}
val activeThemeId by when (action) {
ThemeManagerScreenAction.SELECT_DAY,
ThemeManagerScreenAction.SELECT_NIGHT -> getThemeIdPref().observeAsState()
ThemeManagerScreenAction.MANAGE -> selectedManagerThemeId
}
var themeExtToDelete by remember { mutableStateOf<Extension?>(null) }
content {
DisposableEffect(activeThemeId) {
@@ -135,34 +102,12 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
}
}
val grayColor = LocalContentColor.current.copy(alpha = 0.56f)
if (action == ThemeManagerScreenAction.MANAGE) {
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
) {
this@content.Preference(
onClick = { navController.navigate(
Routes.Ext.Edit("null", ThemeExtension.SERIAL_TYPE)
) },
icon = Icons.Default.Add,
title = stringRes(R.string.ext__editor__title_create_theme),
)
this@content.Preference(
onClick = { navController.navigate(
Routes.Ext.Import(ExtensionImportScreenType.EXT_THEME, null)
) },
icon = Icons.Default.Input,
title = stringRes(R.string.action__import),
)
}
}
for ((extensionId, configs) in extGroupedThemes) key(extensionId) {
val ext = extensionManager.getExtensionById(extensionId)!!
FlorisOutlinedBox(
modifier = Modifier.defaultFlorisOutlinedBox(),
title = ext.meta.title,
onTitleClick = { navController.navigate(Routes.Ext.View(extensionId)) },
subtitle = extensionId,
onSubtitleClick = { navController.navigate(Routes.Ext.View(extensionId)) },
) {
for (config in configs) key(extensionId, config.id) {
JetPrefListItem(
@@ -171,8 +116,8 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
},
icon = {
RadioButton(
selected = activeThemeId?.extensionId == extensionId &&
activeThemeId?.componentId == config.id,
selected = activeThemeId.extensionId == extensionId &&
activeThemeId.componentId == config.id,
onClick = null,
)
},
@@ -191,51 +136,7 @@ fun ThemeManagerScreen(action: ThemeManagerScreenAction?) = FlorisScreen {
},
)
}
if (action == ThemeManagerScreenAction.MANAGE && extensionManager.canDelete(ext)) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 6.dp),
) {
FlorisTextButton(
onClick = {
themeExtToDelete = ext
},
icon = Icons.Default.Delete,
text = stringRes(R.string.action__delete),
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colors.error,
),
)
Spacer(modifier = Modifier.weight(1f))
FlorisTextButton(
onClick = {
navController.navigate(Routes.Ext.Edit(ext.meta.id))
},
icon = Icons.Default.Edit,
text = stringRes(R.string.action__edit),
)
}
}
}
}
if (themeExtToDelete != null) {
FlorisConfirmDeleteDialog(
onConfirm = {
runCatching {
extensionManager.delete(themeExtToDelete!!)
}.onFailure { error ->
context.showLongToast(
R.string.error__snackbar_message,
"error_message" to error.localizedMessage,
)
}
themeExtToDelete = null
},
onDismiss = { themeExtToDelete = null },
what = themeExtToDelete!!.meta.title,
)
}
}
}

View File

@@ -16,35 +16,33 @@
package dev.patrickgold.florisboard.app.settings.theme
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BrightnessAuto
import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.FormatPaint
import androidx.compose.material.icons.filled.LightMode
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.app.ext.AddonManagementReferenceBox
import dev.patrickgold.florisboard.app.ext.ExtensionListScreenType
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.ime.theme.ThemeMode
import dev.patrickgold.florisboard.lib.android.launchUrl
import dev.patrickgold.florisboard.lib.compose.FlorisInfoCard
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.themeManager
import dev.patrickgold.jetpref.datastore.model.observeAsState
import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
@Composable
fun ThemeScreen() = FlorisScreen {
@@ -53,13 +51,21 @@ fun ThemeScreen() = FlorisScreen {
val context = LocalContext.current
val navController = LocalNavController.current
val themeManager by context.themeManager()
@Composable
fun ThemeManager.getThemeLabel(id: ExtensionComponentName): String {
val configs by indexedThemeConfigs.observeAsState()
configs?.get(id)?.let { return it.label }
return id.toString()
}
content {
val themeMode by prefs.theme.mode.observeAsState()
val dayThemeId by prefs.theme.dayThemeId.observeAsState()
val nightThemeId by prefs.theme.nightThemeId.observeAsState()
Card(modifier = Modifier.padding(8.dp)) {
/*Card(modifier = Modifier.padding(8.dp)) {
Column(modifier = Modifier.padding(8.dp)) {
Text("If you want to give feedback on the new stylesheet editor and theme engine, please do so in below linked feedback thread:\n")
Button(onClick = {
@@ -68,13 +74,13 @@ fun ThemeScreen() = FlorisScreen {
Text("Open Feedback Thread")
}
}
}
}*/
ListPreference(
prefs.theme.mode,
icon = Icons.Default.BrightnessAuto,
title = stringRes(R.string.pref__theme__mode__label),
entries = ThemeMode.listEntries(),
entries = enumDisplayEntriesOf(ThemeMode::class),
)
if (themeMode == ThemeMode.FOLLOW_TIME) {
FlorisInfoCard(
@@ -85,53 +91,24 @@ fun ThemeScreen() = FlorisScreen {
)
}
Preference(
icon = Icons.Outlined.Palette,
title = stringRes(R.string.settings__theme_manager__title_manage),
icon = Icons.Default.LightMode,
title = stringRes(R.string.pref__theme__day),
summary = themeManager.getThemeLabel(dayThemeId),
enabledIf = { prefs.theme.mode isNotEqualTo ThemeMode.ALWAYS_NIGHT },
onClick = {
navController.navigate(Routes.Settings.ThemeManager(ThemeManagerScreenAction.MANAGE))
navController.navigate(Routes.Settings.ThemeManager(ThemeManagerScreenAction.SELECT_DAY))
},
)
Preference(
icon = Icons.Default.DarkMode,
title = stringRes(R.string.pref__theme__night),
summary = themeManager.getThemeLabel(nightThemeId),
enabledIf = { prefs.theme.mode isNotEqualTo ThemeMode.ALWAYS_DAY },
onClick = {
navController.navigate(Routes.Settings.ThemeManager(ThemeManagerScreenAction.SELECT_NIGHT))
},
)
PreferenceGroup(
title = stringRes(R.string.pref__theme__day),
enabledIf = { prefs.theme.mode isNotEqualTo ThemeMode.ALWAYS_NIGHT },
) {
Preference(
icon = Icons.Default.LightMode,
title = stringRes(R.string.pref__theme__any_theme__label),
summary = dayThemeId.toString(),
onClick = {
navController.navigate(Routes.Settings.ThemeManager(ThemeManagerScreenAction.SELECT_DAY))
},
)
SwitchPreference(
prefs.theme.dayThemeAdaptToApp,
icon = Icons.Default.FormatPaint,
title = stringRes(R.string.pref__theme__any_theme_adapt_to_app__label),
summary = stringRes(R.string.pref__theme__any_theme_adapt_to_app__summary),
visibleIf = { false },
)
}
PreferenceGroup(
title = stringRes(R.string.pref__theme__night),
enabledIf = { prefs.theme.mode isNotEqualTo ThemeMode.ALWAYS_DAY },
) {
Preference(
icon = Icons.Default.DarkMode,
title = stringRes(R.string.pref__theme__any_theme__label),
summary = nightThemeId.toString(),
onClick = {
navController.navigate(Routes.Settings.ThemeManager(ThemeManagerScreenAction.SELECT_NIGHT))
},
)
SwitchPreference(
prefs.theme.nightThemeAdaptToApp,
icon = Icons.Default.FormatPaint,
title = stringRes(R.string.pref__theme__any_theme_adapt_to_app__label),
summary = stringRes(R.string.pref__theme__any_theme_adapt_to_app__summary),
visibleIf = { false },
)
}
AddonManagementReferenceBox(type = ExtensionListScreenType.EXT_THEME)
}
}

View File

@@ -23,27 +23,27 @@ import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
import dev.patrickgold.florisboard.lib.UnicodeCtrlChar
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.snygg.Snygg
import dev.patrickgold.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.snygg.SnyggRule
import dev.patrickgold.florisboard.lib.snygg.value.RgbaColor
import dev.patrickgold.florisboard.lib.snygg.value.SnyggCircleShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggCutCornerPercentShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDefinedVarValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggDpSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggExplicitInheritValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggImplicitInheritValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouDarkColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggPercentageSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggRectangleShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggRoundedCornerPercentShapeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggSolidColorValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggSpSizeValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggValue
import dev.patrickgold.florisboard.lib.snygg.value.SnyggValueEncoder
import org.florisboard.lib.snygg.Snygg
import org.florisboard.lib.snygg.SnyggLevel
import org.florisboard.lib.snygg.SnyggRule
import org.florisboard.lib.snygg.value.RgbaColor
import org.florisboard.lib.snygg.value.SnyggCircleShapeValue
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
import org.florisboard.lib.snygg.value.SnyggCutCornerPercentShapeValue
import org.florisboard.lib.snygg.value.SnyggDefinedVarValue
import org.florisboard.lib.snygg.value.SnyggDpSizeValue
import org.florisboard.lib.snygg.value.SnyggExplicitInheritValue
import org.florisboard.lib.snygg.value.SnyggImplicitInheritValue
import org.florisboard.lib.snygg.value.SnyggMaterialYouDarkColorValue
import org.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
import org.florisboard.lib.snygg.value.SnyggPercentageSizeValue
import org.florisboard.lib.snygg.value.SnyggRectangleShapeValue
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
import org.florisboard.lib.snygg.value.SnyggRoundedCornerPercentShapeValue
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
import org.florisboard.lib.snygg.value.SnyggSpSizeValue
import org.florisboard.lib.snygg.value.SnyggValue
import org.florisboard.lib.snygg.value.SnyggValueEncoder
import kotlin.math.roundToInt
@Composable

View File

@@ -23,25 +23,25 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.HelpOutline
import androidx.compose.material.icons.automirrored.filled.HelpOutline
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.android.AndroidSettings
import dev.patrickgold.florisboard.lib.android.launchActivity
import dev.patrickgold.florisboard.lib.compose.FlorisCanvasIcon
import dev.patrickgold.florisboard.lib.compose.FlorisErrorCard
import dev.patrickgold.florisboard.lib.compose.FlorisSimpleCard
import dev.patrickgold.florisboard.lib.compose.FlorisWarningCard
import dev.patrickgold.florisboard.lib.compose.observeAsState
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.util.launchActivity
import org.florisboard.lib.android.AndroidSettings
@Composable
fun SpellCheckerServiceSelector(florisSpellCheckerEnabled: MutableState<Boolean>) {
@@ -106,7 +106,7 @@ fun SpellCheckerServiceSelector(florisSpellCheckerEnabled: MutableState<Boolean>
modifier = Modifier
.padding(end = 8.dp)
.requiredSize(32.dp),
imageVector = Icons.Default.HelpOutline,
imageVector = Icons.AutoMirrored.Filled.HelpOutline,
contentDescription = null,
)
}

View File

@@ -18,13 +18,13 @@ package dev.patrickgold.florisboard.app.settings.typing
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.LibraryBooks
import androidx.compose.material.icons.filled.Contacts
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.LibraryBooks
import androidx.compose.material.icons.filled.SpaceBar
import androidx.compose.material3.Card
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -32,8 +32,11 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.compose.FlorisErrorCard
import dev.patrickgold.florisboard.lib.compose.FlorisHyperlinkText
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
@@ -42,6 +45,7 @@ import dev.patrickgold.jetpref.datastore.model.observeAsState
import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
@@ -51,6 +55,8 @@ fun TypingScreen() = FlorisScreen {
title = stringRes(R.string.settings__typing__title)
previewFieldVisible = true
val navController = LocalNavController.current
content {
// This card is temporary and is therefore not using a string resource
FlorisErrorCard(
@@ -146,7 +152,7 @@ fun TypingScreen() = FlorisScreen {
prefs.spelling.languageMode,
icon = Icons.Default.Language,
title = stringRes(R.string.pref__spelling__language_mode__label),
entries = SpellingLanguageMode.listEntries(),
entries = enumDisplayEntriesOf(SpellingLanguageMode::class),
enabledIf = { florisSpellCheckerEnabled.value },
)
SwitchPreference(
@@ -159,12 +165,20 @@ fun TypingScreen() = FlorisScreen {
)
SwitchPreference(
prefs.spelling.useUdmEntries,
icon = Icons.Default.LibraryBooks,
icon = Icons.AutoMirrored.Filled.LibraryBooks,
title = stringRes(R.string.pref__spelling__use_udm_entries__label),
summary = stringRes(R.string.pref__spelling__use_udm_entries__summary),
enabledIf = { florisSpellCheckerEnabled.value },
visibleIf = { false }, // For now
)
}
PreferenceGroup(title = stringRes(R.string.settings__dictionary__title)) {
Preference(
icon = Icons.AutoMirrored.Filled.LibraryBooks,
title = stringRes(R.string.settings__dictionary__title),
onClick = { navController.navigate(Routes.Settings.Dictionary) },
)
}
}
}

View File

@@ -28,8 +28,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -45,9 +45,9 @@ import dev.patrickgold.florisboard.app.FlorisAppActivity
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.android.launchActivity
import dev.patrickgold.florisboard.lib.android.launchUrl
import org.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.util.launchActivity
import dev.patrickgold.florisboard.lib.util.launchUrl
import dev.patrickgold.florisboard.lib.compose.FlorisBulletSpacer
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.FlorisScreenScope

View File

@@ -46,18 +46,17 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ClearAll
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.ToggleOff
import androidx.compose.material.icons.filled.ToggleOn
import androidx.compose.material.icons.filled.Videocam
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -81,7 +80,6 @@ import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.apptheme.Green500
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.ime.ImeUiMode
@@ -92,10 +90,6 @@ import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.android.AndroidKeyguardManager
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.android.showShortToast
import dev.patrickgold.florisboard.lib.android.systemService
import dev.patrickgold.florisboard.lib.compose.FlorisIconButtonWithInnerPadding
import dev.patrickgold.florisboard.lib.compose.FlorisStaggeredVerticalGrid
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
@@ -105,16 +99,21 @@ import dev.patrickgold.florisboard.lib.compose.rippleClickable
import dev.patrickgold.florisboard.lib.compose.safeTimes
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.observeAsNonNullState
import dev.patrickgold.florisboard.lib.snygg.SnyggPropertySet
import dev.patrickgold.florisboard.lib.snygg.ui.SnyggSurface
import dev.patrickgold.florisboard.lib.snygg.ui.snyggBackground
import dev.patrickgold.florisboard.lib.snygg.ui.snyggBorder
import dev.patrickgold.florisboard.lib.snygg.ui.snyggClip
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.NetworkUtils
import dev.patrickgold.jetpref.datastore.model.observeAsState
import org.florisboard.lib.android.AndroidKeyguardManager
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.systemService
import org.florisboard.lib.snygg.SnyggPropertySet
import org.florisboard.lib.snygg.ui.SnyggButton
import org.florisboard.lib.snygg.ui.SnyggSurface
import org.florisboard.lib.snygg.ui.snyggBackground
import org.florisboard.lib.snygg.ui.snyggBorder
import org.florisboard.lib.snygg.ui.snyggClip
import org.florisboard.lib.snygg.ui.snyggShadow
import org.florisboard.lib.snygg.ui.solidColor
import org.florisboard.lib.snygg.ui.spSize
private val ContentPadding = PaddingValues(horizontal = 4.dp)
private val ItemMargin = PaddingValues(all = 6.dp)
@@ -144,6 +143,7 @@ fun ClipboardInputLayout(
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardHeader)
val itemStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardItem)
val popupStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardItemPopup)
val enableHistoryButtonStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardEnableHistoryButton)
fun isPopupSurfaceActive() = popupItem != null || showClearAllHistory
@@ -158,8 +158,7 @@ fun ClipboardInputLayout(
) {
FlorisIconButtonWithInnerPadding(
onClick = { keyboardManager.activeState.imeUiMode = ImeUiMode.TEXT },
modifier = Modifier.autoMirrorForRtl(),
icon = Icons.Default.ArrowBack,
icon = Icons.AutoMirrored.Filled.ArrowBack,
iconColor = headerStyle.foreground.solidColor(context),
)
Text(
@@ -537,21 +536,14 @@ fun ClipboardInputLayout(
color = itemStyle.foreground.solidColor(context),
fontSize = itemStyle.fontSize.spSize(),
)
Button(
SnyggButton(
modifier = Modifier
.padding(top = 8.dp)
.align(Alignment.End),
onClick = { prefs.clipboard.historyEnabled.set(true) },
colors = ButtonDefaults.buttonColors(
backgroundColor = Green500,
contentColor = Color.White,
),
) {
Text(
text = stringRes(R.string.clipboard__disabled__enable_button),
fontSize = itemStyle.fontSize.spSize(),
)
}
style = enableHistoryButtonStyle,
text = stringRes(R.string.clipboard__disabled__enable_button)
)
}
}
}

View File

@@ -28,11 +28,11 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardHistoryDao
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardHistoryDatabase
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
import dev.patrickgold.florisboard.lib.android.AndroidClipboardManager
import dev.patrickgold.florisboard.lib.android.AndroidClipboardManager_OnPrimaryClipChangedListener
import dev.patrickgold.florisboard.lib.android.setOrClearPrimaryClip
import dev.patrickgold.florisboard.lib.android.showShortToast
import dev.patrickgold.florisboard.lib.android.systemService
import org.florisboard.lib.android.AndroidClipboardManager
import org.florisboard.lib.android.AndroidClipboardManager_OnPrimaryClipChangedListener
import org.florisboard.lib.android.setOrClearPrimaryClip
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.systemService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -296,6 +296,34 @@ class ClipboardManager(
}
}
/**
* Restore the clipboard history from a [List]
*
* @param shouldReset if the history should be reset
* @param items the [ClipboardItem] list with the new items
*/
fun restoreHistory(items: List<ClipboardItem>, shouldReset: Boolean, itemType: ItemType) {
ioScope.launch {
if (shouldReset) {
for (item in history().all) {
item.close(appContext)
}
clipHistoryDao?.deleteAllFromType(itemType)
for (item in items) {
this@ClipboardManager.insertClip(item.copy(id = 0))
}
} else {
val currentHistory = this@ClipboardManager.history().all
for (item in items) {
if (!currentHistory.map { it.copy(id = 0) }.contains(item.copy(id = 0))) {
this@ClipboardManager.insertClip(item.copy(id = 0))
}
}
}
}
}
fun deleteClip(item: ClipboardItem) {
ioScope.launch {
clipHistoryDao?.delete(item)

View File

@@ -39,7 +39,9 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import androidx.room.Update
import dev.patrickgold.florisboard.lib.android.query
import org.florisboard.lib.android.UriSerializer
import org.florisboard.lib.android.query
import kotlinx.serialization.Serializable
import org.florisboard.lib.kotlin.tryOrNull
private const val CLIPBOARD_HISTORY_TABLE = "clipboard_history"
@@ -63,6 +65,7 @@ enum class ItemType(val value: Int) {
* If type == ItemType.IMAGE there must be a uri set
* if type == ItemType.TEXT there must be a text set
*/
@Serializable
@Entity(tableName = CLIPBOARD_HISTORY_TABLE)
data class ClipboardItem(
@PrimaryKey(autoGenerate = true)
@@ -70,6 +73,7 @@ data class ClipboardItem(
var id: Long = 0,
val type: ItemType,
val text: String?,
@Serializable(with = UriSerializer::class)
val uri: Uri?,
val creationTimestampMs: Long,
val isPinned: Boolean,
@@ -282,6 +286,9 @@ interface ClipboardHistoryDao {
@Query("DELETE FROM $CLIPBOARD_HISTORY_TABLE")
fun deleteAll()
@Query("DELETE FROM $CLIPBOARD_HISTORY_TABLE WHERE type = :type")
fun deleteAllFromType(type: ItemType)
@Query("DELETE FROM $CLIPBOARD_HISTORY_TABLE WHERE NOT isPinned")
fun deleteAllUnpinned()
}
@@ -303,6 +310,7 @@ abstract class ClipboardHistoryDatabase : RoomDatabase() {
}
}
@Serializable
@Entity(tableName = CLIPBOARD_FILES_TABLE)
data class ClipboardFileInfo(
@PrimaryKey @ColumnInfo(name=BaseColumns._ID, index=true) val id: Long,

View File

@@ -18,16 +18,18 @@ package dev.patrickgold.florisboard.ime.clipboard.provider
import android.content.Context
import android.net.Uri
import dev.patrickgold.florisboard.lib.android.readToFile
import dev.patrickgold.florisboard.lib.devtools.LogTopic
import dev.patrickgold.florisboard.lib.devtools.flogDebug
import dev.patrickgold.florisboard.lib.io.FsFile
import dev.patrickgold.florisboard.lib.io.subFile
import org.florisboard.lib.android.readToFile
import org.florisboard.lib.kotlin.io.FsFile
import org.florisboard.lib.kotlin.io.subFile
/**
* Backend helper object which is used by [ClipboardMediaProvider] to serve content.
*/
object ClipboardFileStorage {
const val CLIPBOARD_FILES_PATH = "clipboard_files"
private val Context.clipboardFilesDir: FsFile
get() = FsFile(this.noBackupFilesDir, "clipboard_files").also { it.mkdirs() }
@@ -58,4 +60,8 @@ object ClipboardFileStorage {
fun getFileForId(context: Context, id: Long): FsFile {
return context.clipboardFilesDir.subFile(id.toString())
}
fun instertFileFromBackup(context: Context, file: FsFile) {
file.copyTo(context.clipboardFilesDir.subFile(file.name), overwrite = false)
}
}

View File

@@ -16,11 +16,6 @@
package dev.patrickgold.florisboard.ime.core
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
/**
* DisplayLocalesIn indicates how language names should be visually presented to the user.
*/
@@ -29,22 +24,4 @@ enum class DisplayLanguageNamesIn {
SYSTEM_LOCALE,
/** Language names are displayed in the locale referred by itself. */
NATIVE_LOCALE;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = SYSTEM_LOCALE,
label = stringRes(R.string.enum__display_language_names_in__system_locale),
description = stringRes(R.string.enum__display_language_names_in__system_locale__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = NATIVE_LOCALE,
label = stringRes(R.string.enum__display_language_names_in__native_locale),
description = stringRes(R.string.enum__display_language_names_in__native_locale__description),
showDescriptionOnlyIfSelected = true,
)
}
}
}

View File

@@ -73,6 +73,15 @@ data class Subtype(
)
}
/**
* Returns an accumulated list of all locales of this subtype.
*/
fun locales(): List<FlorisLocale> {
val locales = mutableListOf(primaryLocale)
locales.addAll(secondaryLocales)
return locales
}
/**
* Converts this object into its short string representation, used for debugging. Format:
* <id>/<language_tag>/<currency_set_name>

View File

@@ -36,8 +36,8 @@ import androidx.room.Update
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.FlorisLocale
import dev.patrickgold.florisboard.lib.ValidationRule
import dev.patrickgold.florisboard.lib.android.readText
import dev.patrickgold.florisboard.lib.android.writeText
import org.florisboard.lib.android.readText
import org.florisboard.lib.android.writeText
import org.florisboard.lib.kotlin.tryOrNull
import java.lang.ref.WeakReference

View File

@@ -38,8 +38,8 @@ import dev.patrickgold.florisboard.ime.text.composing.Appender
import dev.patrickgold.florisboard.ime.text.composing.Composer
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.showShortToast
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
import dev.patrickgold.florisboard.nlpManager
import dev.patrickgold.florisboard.subtypeManager

View File

@@ -1,25 +1,6 @@
package dev.patrickgold.florisboard.ime.input
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
enum class CapitalizationBehavior {
CAPSLOCK_BY_DOUBLE_TAP,
CAPSLOCK_BY_CYCLE;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = CAPSLOCK_BY_DOUBLE_TAP,
label = stringRes(R.string.enum__capitalization_behavior__capslock_by_double_tap),
)
entry(
key = CAPSLOCK_BY_CYCLE,
label = stringRes(R.string.enum__capitalization_behavior__capslock_by_cycle),
)
}
}
}

View File

@@ -16,30 +16,7 @@
package dev.patrickgold.florisboard.ime.input
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
enum class HapticVibrationMode {
USE_VIBRATOR_DIRECTLY,
USE_HAPTIC_FEEDBACK_INTERFACE;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = USE_VIBRATOR_DIRECTLY,
label = stringRes(R.string.enum__haptic_vibration_mode__use_vibrator_directly),
description = stringRes(R.string.enum__haptic_vibration_mode__use_vibrator_directly__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = USE_HAPTIC_FEEDBACK_INTERFACE,
label = stringRes(R.string.enum__haptic_vibration_mode__use_haptic_feedback_interface),
description = stringRes(R.string.enum__haptic_vibration_mode__use_haptic_feedback_interface__description),
showDescriptionOnlyIfSelected = true,
)
}
}
}

View File

@@ -26,7 +26,7 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.lib.android.removeAndReturn
import org.florisboard.lib.android.removeAndReturn
import dev.patrickgold.florisboard.lib.devtools.flogDebug
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@@ -16,38 +16,7 @@
package dev.patrickgold.florisboard.ime.input
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
enum class InputFeedbackActivationMode {
RESPECT_SYSTEM_SETTINGS,
IGNORE_SYSTEM_SETTINGS;
companion object {
@Composable
fun audioListEntries() = listPrefEntries {
entry(
key = RESPECT_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__audio_respect_system_settings),
)
entry(
key = IGNORE_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__audio_ignore_system_settings),
)
}
@Composable
fun hapticListEntries() = listPrefEntries {
entry(
key = RESPECT_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__haptic_respect_system_settings),
)
entry(
key = IGNORE_SYSTEM_SETTINGS,
label = stringRes(R.string.enum__input_feedback_activation_mode__haptic_ignore_system_settings),
)
}
}
}

View File

@@ -25,10 +25,10 @@ import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.lib.android.AndroidVersion
import dev.patrickgold.florisboard.lib.android.systemServiceOrNull
import dev.patrickgold.florisboard.lib.android.systemVibratorOrNull
import dev.patrickgold.florisboard.lib.android.vibrate
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.systemServiceOrNull
import org.florisboard.lib.android.systemVibratorOrNull
import org.florisboard.lib.android.vibrate
import dev.patrickgold.florisboard.lib.devtools.flogDebug
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers

View File

@@ -42,12 +42,10 @@ import androidx.compose.material.icons.filled.SelectAll
import androidx.compose.material.icons.filled.Send
import androidx.compose.material.icons.filled.SentimentSatisfiedAlt
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Smartphone
import androidx.compose.material.icons.filled.SpaceBar
import androidx.compose.material.icons.filled.Undo
import androidx.compose.material.icons.outlined.Assignment
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
import dev.patrickgold.florisboard.ime.core.Subtype
@@ -209,8 +207,7 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
}
KeyCode.COMPACT_LAYOUT_TO_LEFT,
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> {
// TODO: find a better icon for compact mode
Icons.Default.Smartphone
context()?.vectorResource(id = R.drawable.ic_accessibility_one_handed)
}
KeyCode.VOICE_INPUT -> {
Icons.Default.KeyboardVoice
@@ -276,9 +273,9 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
}
KeyCode.TOGGLE_INCOGNITO_MODE -> {
if (evaluator.state.isIncognitoMode) {
ImageVector.vectorResource(theme = null, resId = R.drawable.ic_incognito, res = this.context()?.resources!!)
this.context()?.vectorResource(id = R.drawable.ic_incognito)
} else {
ImageVector.vectorResource(theme = null, resId = R.drawable.ic_incognito_off, res = this.context()?.resources!!)
this.context()?.vectorResource(id = R.drawable.ic_incognito_off)
}
}
KeyCode.TOGGLE_AUTOCORRECT -> {

View File

@@ -36,7 +36,7 @@ import dev.patrickgold.florisboard.ime.smartbar.ExtendedActionsPlacement
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyboard
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.android.isOrientationLandscape
import org.florisboard.lib.android.isOrientationLandscape
import dev.patrickgold.florisboard.lib.observeAsTransformingState
import dev.patrickgold.florisboard.lib.util.ViewUtils
import dev.patrickgold.jetpref.datastore.model.observeAsState

View File

@@ -16,37 +16,8 @@
package dev.patrickgold.florisboard.ime.keyboard
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
enum class IncognitoMode {
FORCE_OFF,
FORCE_ON,
DYNAMIC_ON_OFF;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = FORCE_OFF,
label = stringRes(R.string.enum__incognito_mode__force_off),
description = stringRes(R.string.enum__incognito_mode__force_off__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = DYNAMIC_ON_OFF,
label = stringRes(R.string.enum__incognito_mode__dynamic_on_off),
description = stringRes(R.string.enum__incognito_mode__dynamic_on_off__description),
showDescriptionOnlyIfSelected = true,
)
entry(
key = FORCE_ON,
label = stringRes(R.string.enum__incognito_mode__force_on),
description = stringRes(R.string.enum__incognito_mode__force_on__description),
showDescriptionOnlyIfSelected = true,
)
}
}
}

View File

@@ -55,10 +55,10 @@ import dev.patrickgold.florisboard.ime.text.key.KeyType
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyboardCache
import dev.patrickgold.florisboard.lib.android.AndroidKeyguardManager
import dev.patrickgold.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.android.showShortToast
import dev.patrickgold.florisboard.lib.android.systemService
import org.florisboard.lib.android.AndroidKeyguardManager
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.android.systemService
import dev.patrickgold.florisboard.lib.devtools.LogTopic
import dev.patrickgold.florisboard.lib.devtools.flogError
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
@@ -942,6 +942,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
}
KeyCode.CLIPBOARD_PASTE -> {
!androidKeyguardManager.let { it.isDeviceLocked || it.isKeyguardLocked }
&& clipboardManager.canBePasted(clipboardManager.primaryClip)
}
KeyCode.CLIPBOARD_CLEAR_PRIMARY_CLIP -> {
clipboardManager.canBePasted(clipboardManager.primaryClip)

View File

@@ -19,7 +19,6 @@ package dev.patrickgold.florisboard.ime.keyboard
import android.content.Context
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.appContext
import dev.patrickgold.florisboard.assetManager
import dev.patrickgold.florisboard.extensionManager
import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.popup.PopupMapping
@@ -34,6 +33,7 @@ import dev.patrickgold.florisboard.lib.devtools.flogDebug
import dev.patrickgold.florisboard.lib.devtools.flogWarning
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
import dev.patrickgold.florisboard.lib.io.ZipUtils
import dev.patrickgold.florisboard.lib.io.loadJsonAsset
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
@@ -69,7 +69,6 @@ private data class CachedPopupMapping(
class LayoutManager(context: Context) {
private val prefs by florisPreferenceModel()
private val appContext by context.appContext()
private val assetManager by context.assetManager()
private val extensionManager by context.extensionManager()
private val keyboardManager by context.keyboardManager()
@@ -101,7 +100,7 @@ class LayoutManager(context: Context) {
val layout = async {
runCatching {
val jsonStr = ZipUtils.readFileFromArchive(appContext, ext.sourceRef!!, path).getOrThrow()
val arrangement = assetManager.loadJsonAsset<LayoutArrangement>(jsonStr).getOrThrow()
val arrangement = loadJsonAsset<LayoutArrangement>(jsonStr).getOrThrow()
CachedLayout(ltn.type, ltn.name, meta, arrangement)
}
}
@@ -128,7 +127,7 @@ class LayoutManager(context: Context) {
val popupMapping = async {
runCatching {
val jsonStr = ZipUtils.readFileFromArchive(appContext, ext.sourceRef!!, path).getOrThrow()
val mapping = assetManager.loadJsonAsset<PopupMapping>(jsonStr).getOrThrow()
val mapping = loadJsonAsset<PopupMapping>(jsonStr).getOrThrow()
CachedPopupMapping(name, meta, mapping)
}
}

View File

@@ -1,30 +1,7 @@
package dev.patrickgold.florisboard.ime.keyboard
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
enum class SpaceBarMode {
NOTHING,
CURRENT_LANGUAGE,
SPACE_BAR_KEY;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = NOTHING,
label = stringRes(R.string.enum__space_bar_mode__nothing),
)
entry(
key = CURRENT_LANGUAGE,
label = stringRes(R.string.enum__space_bar_mode__current_language),
)
entry(
key = SPACE_BAR_KEY,
label = stringRes(R.string.enum__space_bar_mode__space_bar_key),
)
}
}
}

View File

@@ -16,31 +16,8 @@
package dev.patrickgold.florisboard.ime.landscapeinput
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
enum class LandscapeInputUiMode {
NEVER_SHOW,
ALWAYS_SHOW,
DYNAMICALLY_SHOW;
companion object {
@Composable
fun listEntries() = listPrefEntries {
entry(
key = NEVER_SHOW,
label = stringRes(R.string.enum__landscape_input_ui_mode__never_show),
)
entry(
key = ALWAYS_SHOW,
label = stringRes(R.string.enum__landscape_input_ui_mode__always_show),
)
entry(
key = DYNAMICALLY_SHOW,
label = stringRes(R.string.enum__landscape_input_ui_mode__dynamically_show),
)
}
}
}

View File

@@ -28,11 +28,10 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Backspace
import androidx.compose.material.icons.outlined.Backspace
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
@@ -45,23 +44,20 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.input.InputEventDispatcher
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.media.emoji.EmojiData
import dev.patrickgold.florisboard.ime.media.emoji.EmojiPaletteView
import dev.patrickgold.florisboard.ime.media.emoji.PlaceholderLayoutDataMap
import dev.patrickgold.florisboard.ime.media.emoji.parseRawEmojiSpecsFile
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.snygg.ui.SnyggSurface
import org.florisboard.lib.snygg.ui.SnyggSurface
@SuppressLint("MutableCollectionMutableState")
@Composable
@@ -71,9 +67,9 @@ fun MediaInputLayout(
val context = LocalContext.current
val keyboardManager by context.keyboardManager()
var emojiLayoutDataMap by remember { mutableStateOf(PlaceholderLayoutDataMap) }
var emojiLayoutDataMap by remember { mutableStateOf(EmojiData.Fallback) }
LaunchedEffect(Unit) {
emojiLayoutDataMap = parseRawEmojiSpecsFile(context, "ime/media/emoji/root.txt")
emojiLayoutDataMap = EmojiData.get(context, "ime/media/emoji/root.txt")
}
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {

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