Compare commits

...

255 Commits

Author SHA1 Message Date
lm41
66491c27fc Make emoji history scrollable 2025-07-26 13:46:31 +02:00
Lars Mühlbauer
c55a87862f Remove enforcement for navigationBarContrast (#2987)
* Remove enforcement for navigationBarContrast

* Use luminance for color contrast detection

* Always use light icons when background image is present
2025-07-22 01:10:29 +02:00
Patrick Goldinger
ee08c58db2 Release v0.5.0-beta02 2025-07-18 15:59:23 +02:00
Patrick Goldinger
05d4a5cf62 Update README.md (#2984)
Updates the milestone version numbers
2025-07-18 15:56:38 +02:00
florisboard-bot
c5c8f7a4c3 Update translations from Crowdin 2025-07-18 15:44:11 +02:00
Patrick Goldinger
ce3aee93d6 Merge pull request #2719 from florisboard/reproducible-builds
Add support for reproducible builds
2025-07-18 15:25:00 +02:00
Patrick Goldinger
96340f7277 Remove old flake build config 2025-07-16 23:11:28 +02:00
Patrick Goldinger
d0dcf5be38 Improve repr_build assemble.sh script 2025-07-16 23:03:09 +02:00
Patrick Goldinger
15450a760e Add ability for APK/AAB signing in repr_build setup 2025-07-16 22:28:14 +02:00
Patrick Goldinger
de0027d87e Add Gradle cache sharing & Add sha256sum generation 2025-07-16 20:24:03 +02:00
Patrick Goldinger
c7e83fca21 Add option to pass custom output directory 2025-07-16 15:29:11 +02:00
Lars Mühlbauer
115dc5c42a Add support for physical keyboard settings (#2981) 2025-07-16 14:41:49 +02:00
Patrick Goldinger
c78cf84d6c Fix Android SDK location and rename to repr_build 2025-07-16 12:58:03 +02:00
Lars Mühlbauer
5e59f144dd Update ROADMAP.md (#2980)
* Update ROADMAP.md

This commit updated the roadmap to include the latest changes,
especially that the 0.5 update was split and word suggestions
are pushed down to 0.6.

* Add time base theme switching to ROADMAP

* Mark spaces in uri bug as fixed in ROADMAP

* Fix typos
2025-07-16 00:55:59 +02:00
Patrick Goldinger
564c075763 Fix files with spaces causing UI issues (#2982) 2025-07-16 00:31:49 +02:00
Lars Mühlbauer
86365d393b Re-add time based theme switching (#2977)
* Add prefs for time based theme switching

* Implement time based theme switching

* Update to jetpref 0.2.0-rc04

* Remove hardcoded strings
2025-07-15 23:56:44 +02:00
Patrick Goldinger
45a0c9ef63 Upgrade gradle/actions/wrapper-validation to v4 2025-07-15 23:16:42 +02:00
Patrick Goldinger
25da6be1a4 Upgrade CMake to 4.0.2 2025-07-15 23:15:01 +02:00
Patrick Goldinger
976afc2e51 Fiz containerization failing for aab builds 2025-07-15 22:47:39 +02:00
Patrick Goldinger
d994da8c97 Rework containerization and add track logic 2025-07-15 22:30:31 +02:00
Patrick Goldinger
40a22a762a Add containerization config for building the project 2025-07-15 16:53:18 +02:00
Patrick Goldinger
264b9ff98b Add -Wl,--build-id=none linker option
Required for reproducible builds to work
2025-07-15 16:52:54 +02:00
Patrick Goldinger
f1b7ddedb8 Add new tools version catalog 2025-07-15 16:51:53 +02:00
Lars Mühlbauer
b1665f61e5 Remove checks for API 26 as this is the min API (#2972) 2025-07-15 11:49:29 +02:00
Patrick Goldinger
0fa663f658 Release v0.5.0-beta01 2025-07-11 00:54:31 +02:00
florisboard-bot
b7f5bf267d Update translations from Crowdin 2025-07-11 00:08:54 +02:00
Lars Mühlbauer
8563f37c98 Refactor FlorisCopyToClipboardActivity (#2968)
* Refactor FlorisCopyToClipboardActivity

* Apply review suggestions
2025-07-10 22:13:05 +02:00
Patrick Goldinger
d3a2e50dda Merge pull request #2963 from florisboard/fix/font-import-mime-types
Relax font mime-type importing restrictions
2025-07-10 12:23:48 +02:00
Patrick Goldinger
29562c9980 Add custom MimeTypeFilter 2025-07-09 14:02:22 +02:00
Patrick Goldinger
5bbb5cfbce Relax font mime-type importing restrictions (#2957) 2025-07-09 14:02:22 +02:00
Lars Mühlbauer
4ada583418 Remove obsolete api level check and simplify logic (#2967)
* Remove obsolete api level check and simplify logic

* Remove obsolete min api level checks
2025-07-09 01:42:46 +02:00
eqilnou
200a195ae6 Add subscripts and missing fractions in number row popups (#2947)
* Add subscripts and missing fractions in western arabic number row

Add subscripts and missing fractions (1/ and 0/3) in western_arabic.json number row layout

* Add subscripts and missing fractions in bengali number row

Added subscripts and missing fractions (1/ and 0/3) in bengali.json number row layout

* Fix ordering of hints for character "1" in western arabic number row

* Add subscripts and missing fractions in devanagari number row

Added subscripts and missing fractions (1/ and 0/3) in devanagari.json number row layout

* Add subscripts and missing fractions in eastern arabic number row

Added subscripts and missing fractions (1/ and 0/3) in eastern_arabic.json number row layout

* Add subscripts and missing fractions in gujarati number row

Added subscripts and missing fractions (1/ and 0/3) in gujarati.json number row layout

* Add subscripts and missing fractions in gurmukhi number row

Added subscripts and missing fractions (1/ and 0/3) in gurmukhi.json number row layout

* Add subscripts and missing fractions in kannada number row

Added subscripts and missing fractions in kannada.json number row layout

* Add subscripts and missing fractions in malayalam number row

Added subscripts and missing fractions in malayalam.json number row layout

* Add subscripts and missing fractions in oriya number row layout

Added subscripts and missing fractions in oriya.json number row layout

* Add subscripts and missing fractions in persian number row

Added subscripts and missing fractions in persian.json number row layout

* Add subscripts and missing fractions in tamil number row

Added subscripts and missing fractions in tamil.json number row layout

* Add subscripts and missing fractions in telugu number row

Added subscripts and missing fractions in telugu.json number row layout

* Add subscripts and missing fractions in warang_citi number row

Added subscripts and missing fractions in warang_citi.json number row layout

* Add subscripts and missing fractions in thai number row

Added subscripts and missing fractions in thai.json number row layout

* Fix ordering of fractions 3/n in western arabic number row

* Fix ordering of fractions 3/n in thai number row

* Fix label of digit '4' in cjk number row

Use the correct symbol U+FF14 instead of U+FF13
2025-07-09 01:16:13 +02:00
MikayelB
fa910692bc Fix Amenian phonetic layout addition (#2904) 2025-07-09 01:02:39 +02:00
Patrick Goldinger
c3545d1625 Merge pull request #2966 from florisboard/chore/update-gradle-and-fix-release-build
Update gradle and fix build error [ExtraTranslation]
2025-07-09 00:55:48 +02:00
lm41
300ca755ec Update to gradle version 8.14.3 2025-07-08 21:20:54 +02:00
lm41
3efb760787 Ignore extra translations when building FlorisBoard 2025-07-08 16:23:10 +02:00
Lars Mühlbauer
647f7c106b Fix always enabling one-hand mode after prefs migration (#2962) 2025-07-07 19:55:35 +02:00
Lars Mühlbauer
d998f8fe0c Fix numbering in setup screen on api < 33 (Android 13 and below) (#2960) 2025-07-07 19:48:14 +02:00
Lars Mühlbauer
b7020d7cc9 Fix gestures not working on api 34+ (Android 14+) (#2959) 2025-07-07 19:44:16 +02:00
Patrick Goldinger
5b874fc22a Release v0.5.0-alpha04 2025-06-04 00:36:53 +02:00
Patrick Goldinger
4a6fad851c Upgrade to Gradle 8.14.1 2025-06-04 00:36:05 +02:00
florisboard-bot
6de6b37f6f Update translations from Crowdin 2025-06-03 23:44:35 +02:00
Patrick Goldinger
d2eb6fd1c4 Merge pull request #2938 from florisboard/feat/clipboard-sorting-and-timestamps
Clipboard filtering and timestamp display
2025-06-03 23:41:53 +02:00
Patrick Goldinger
4b84a1ed40 Adapt other default themes to new element names/styles 2025-06-03 23:17:02 +02:00
Patrick Goldinger
a1d4079ef9 Add display of clipboard timestamps (#2926) 2025-06-03 23:11:10 +02:00
Patrick Goldinger
ba6d401447 Add style for clipboard item description and improve icons
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-31 16:17:24 +02:00
Patrick Goldinger
43168fc31f Add SnyggChip
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-31 16:17:24 +02:00
Patrick Goldinger
d234d30154 Improve clipboard item style
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-31 16:17:24 +02:00
Patrick Goldinger
e010a22863 Add clipboard filter by item type (#2925)
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-31 16:17:24 +02:00
Patrick Goldinger
da3b99fda8 Upgrade to Compose 1.8 and Migrate to Compose BOM (#2931)
* Upgrade AGP to 8.9.3 and Gradle to 8.11.1

* Upgrade to Compose 1.8 & Migrate to Compose BOM
2025-05-31 16:14:14 +02:00
Patrick Goldinger
23f58496e3 Upgrade to Compose 1.8 & Migrate to Compose BOM 2025-05-31 16:08:29 +02:00
Patrick Goldinger
40ecbe1428 Upgrade AGP to 8.9.3 and Gradle to 8.11.1 2025-05-30 13:34:40 +02:00
szgabor3
62a2131fa8 Update hu.json (#2922)
I suggest modifications for main alternatives to key 
o -> ó instead of ö
u -> ú instead of ü
as those (ö and ü) already have their own keys on the keyboard.
So this way the main alternatives fit better to the similars (e.g. a-á, e-é, i-í) and the layout becomes more conveniently usable.
2025-05-27 20:51:50 +02:00
Patrick Goldinger
df8f96396f Merge pull request #2927 from florisboard/feat/clipboard-history-improvements
Clipboard history UI improvements
2025-05-25 01:48:27 +02:00
Patrick Goldinger
bace0259ec Rework element names of clipboard item popup (#2908) 2025-05-25 01:37:35 +02:00
Patrick Goldinger
64f062307d Remove restriction of clipboard item visible character length (#2900) 2025-05-25 01:18:24 +02:00
Patrick Goldinger
2ca69f8fa9 Rework clipboard history grid implementation (#2906) 2025-05-25 01:09:29 +02:00
Lars Mühlbauer
f8537a2245 Move the checklist to the bottom and correct typos (#2924) 2025-05-24 22:54:27 +02:00
Patrick Goldinger
cdb6707850 Fix theme editor navbar color bug (#2920) 2025-05-21 01:19:11 +02:00
Patrick Goldinger
35db9be1bf Revert "Fix ignored paths not applied to pull_request in workflow (#2917)" (#2919)
This reverts commit 8551bb6842.
2025-05-21 00:43:05 +02:00
Patrick Goldinger
8551bb6842 Fix ignored paths not applied to pull_request in workflow (#2917) 2025-05-21 00:28:59 +02:00
Patrick Goldinger
9ad5bc68d3 Improve issue templates, contrib guidelines, and roadmap (#2916)
* Improve repo issue templates

Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>

* Improve repo contribution guidelines

Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>

* Adjust roadmap to 0.5 dev cycle

Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>

---------

Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-21 00:16:23 +02:00
klaurence
ebf5c0f898 Fix one-handed button migration (#2907)
* Update AppPrefs.kt

* Fix one-handed button migration (florisboard/florisboard#2905)

* Fix accidentally-missing brace

* Try to fix null exception
2025-05-15 22:47:52 +02:00
Patrick Goldinger
f913b4f7db Release v0.5.0-alpha03 2025-05-14 02:08:57 +02:00
florisboard-bot
4f966385ec Update translations from Crowdin 2025-05-14 02:05:58 +02:00
Patrick Goldinger
e2ce63a2e9 Add mode attribute to select element styles (#2899)
* Add `mode` attribute to element styles

Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>

* Add `mode` attribute to key popup elements

---------

Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-14 02:04:07 +02:00
Patrick Goldinger
64603c4692 Fix theme state bugs (#2897)
Also enable Compose strong skipping mode
2025-05-13 22:50:13 +02:00
Patrick Goldinger
90d3fbfdf1 Merge pull request #2895 from florisboard/fix/smartbar-default-style
Fix Smartbar styles (actions, candidates, ...)
2025-05-13 20:34:54 +02:00
Patrick Goldinger
1f01c56c68 Fix font size multiplier not having any effect (#2896) 2025-05-13 20:21:15 +02:00
MikayelB
c0a5486619 Fix Armenian layout in extension.json (#2871)
The Armenian Alt Phonetic json was configured but wasn't properly added to extension.json, that's why it doesn't show up in the layout menu.
2025-05-13 02:51:58 +02:00
Patrick Goldinger
511802cb25 Disallow clip on window element styles 2025-05-13 01:18:09 +02:00
Patrick Goldinger
eb057ecaf5 Fix Smartbar extended actions style (#2881) 2025-05-13 01:11:21 +02:00
Patrick Goldinger
f93938b43a Allow fine-tuned styling of Smartbar candidates (#2887) 2025-05-13 00:44:56 +02:00
Patrick Goldinger
2b7f8212c7 Allow fine-tuned styling of Smartbar action tiles (#2887) 2025-05-13 00:15:00 +02:00
Patrick Goldinger
44c2c6e9c1 Fix fallback style of Smartbar shared actions toggle 2025-05-12 23:29:22 +02:00
Patrick Goldinger
a2cfe091a6 Add SnyggListItem / Allow styling of subtype pnale list items (#2893)
* Add SnyggListItem and allow subtype list to be styled (#2885)

* Update default themes regarding subtype panel style

* Fix text overflow issues for default subtype panel list item style
2025-05-12 23:16:54 +02:00
Patrick Goldinger
4d9b4d5522 Merge pull request #2890 from florisboard/fix/snygg-v2-minor-issues
Small fixes in new theme editor
2025-05-11 10:57:51 +02:00
Patrick Goldinger
defe45fec6 Fix theme editor rules being cut off (#2888) 2025-05-10 22:15:16 +02:00
Patrick Goldinger
c6721067bf Fix translation error in media theme category (#2886) 2025-05-10 21:54:33 +02:00
Patrick Goldinger
a7f55d4589 Fix theme manager dropdown state not updating (#2876) 2025-05-10 00:35:34 +02:00
Patrick Goldinger
eb2e260924 Fix version suffix missing minus delimiter (#2874) (#2875) 2025-05-09 23:48:54 +02:00
Patrick Goldinger
4950533409 Add distinct filtering to Smartbar quick actions in prefs migration
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-09 22:16:28 +02:00
Patrick Goldinger
813047fb40 Add option to reset Smartbar quick actions from devtools 2025-05-09 22:16:28 +02:00
Patrick Goldinger
96f3dccfc2 Fix Smartbar quick actions duplicated in prefs migration
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-09 22:16:28 +02:00
Patrick Goldinger
65595076ee Release v0.5.0-alpha02 2025-05-09 00:42:58 +02:00
florisboard-bot
bf1563ae78 Update translations from Crowdin 2025-05-09 00:33:24 +02:00
Patrick Goldinger
d111771e06 Upgrade jetpref and compose-tooltip 2025-05-09 00:29:24 +02:00
Patrick Goldinger
00ce01e102 Fix inline autofill chip style (#2868) 2025-05-07 00:59:10 +02:00
Patrick Goldinger
15b7022204 Improve Select files screen UX (#2859, #2860)
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-07 00:27:00 +02:00
Lars Mühlbauer
759b7f0033 Add language switch option to smartbar (#2816)
* Add language switch option to smartbar.

* Only enable switch language button when there are multiple subtypes
2025-05-06 23:31:23 +02:00
Lars Mühlbauer
73c3777529 Add transparent navigation bar to android xml themes (#2867) 2025-05-06 22:54:28 +02:00
Patrick Goldinger
a365e76383 Release v0.5.0-alpha01 2025-05-04 03:58:50 +02:00
florisboard-bot
7c4747d451 Update translations from Crowdin 2025-05-04 03:49:59 +02:00
Patrick Goldinger
12be43e100 Merge pull request #2855 from florisboard/feat/snyggv2
Theme rework part II (Snygg v2)
2025-05-04 03:41:36 +02:00
klaurence
207cf244e6 Change "Material you" to "Material You" (#2827) 2025-05-04 03:36:47 +02:00
lm41
6f45cf8456 Remove println 2025-05-04 03:34:42 +02:00
Patrick Goldinger
5b73de5700 Add and improve theme translations
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-04 03:06:30 +02:00
Patrick Goldinger
25c94e8270 Fix SnyggBox image sizing and SnyggText clipping
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-04 01:48:43 +02:00
Patrick Goldinger
0cd703427a Fix custom rule ordering and other issues in theme editor
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-04 00:00:41 +02:00
Patrick Goldinger
3871978abc Add custom sorting of element names in theme editor 2025-05-03 22:26:57 +02:00
lm41
a9502be471 Improve import addons UX for themes 2025-05-03 17:41:45 +02:00
lm41
a5f2844488 Rework floris_pure_night and floris_pure_night_borderless stylesheets 2025-05-03 16:53:01 +02:00
lm41
dd67497154 Rework floris_night and floris_night_borderless stylesheets 2025-05-03 16:38:44 +02:00
lm41
01c7512c01 Improve floris_day_borderless theme 2025-05-03 15:56:13 +02:00
Patrick Goldinger
fe37ea914c Revert "Enable compose strong skipping mode"
This reverts commit fa768c0e2a.
2025-05-03 15:39:30 +02:00
Patrick Goldinger
fa768c0e2a Enable compose strong skipping mode 2025-05-03 15:01:12 +02:00
Patrick Goldinger
bcd3d1719b Add TODO for nav bar color issue 2025-05-02 04:57:15 +02:00
Patrick Goldinger
55f881d8a0 Fix inline suggestions UI style bundle not being returned 2025-05-02 04:23:55 +02:00
Patrick Goldinger
cd817dec93 Continue adapting base style and IME UI
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-05-02 04:17:56 +02:00
lm41
cdf8bc2825 Move all colors to the @defines block in floris_day 2025-05-01 23:39:45 +02:00
lm41
62d07b0142 Re-introduce SnyggIconButton
This commit reverts some parts of the previous commit
as it massively broke the layout.
2025-05-01 16:19:33 +02:00
lm41
f50cd2de58 Add and improve docs for the Snygg ui components
Co-authored-by: Patrick Goldinger <patrick@patrickgold.dev>
2025-05-01 02:32:00 +02:00
lm41
396a47cde9 Improve docs for SnyggUi 2025-04-30 19:11:12 +02:00
lm41
51e67c7293 Add docs for SnyggIcon and SnyggText 2025-04-30 19:10:39 +02:00
Patrick Goldinger
0bc64c6253 Rework SnyggButton and adapt clipboard clear all dialog style 2025-04-30 02:32:58 +02:00
Patrick Goldinger
f571013fe5 Add custom font name dropdown in theme editor 2025-04-30 01:31:06 +02:00
Patrick Goldinger
5f7ca53458 Fix Snygg rule ordering issue with selectors 2025-04-30 00:14:47 +02:00
Patrick Goldinger
0cacb9a671 Enforce presence of correct schema reference in Snygg stylesheet 2025-04-29 23:52:13 +02:00
lm41
30d36b7541 Improve extension archive file manager screen 2025-04-29 23:08:28 +02:00
Patrick Goldinger
3ece15f516 Continue adaption of base style to Snygg v2 2025-04-28 05:18:41 +02:00
Patrick Goldinger
603fab1831 Add Snygg serialization exceptions and detailed error explanation for missing schema 2025-04-28 04:26:36 +02:00
Patrick Goldinger
90838012ad Add error handling and display for stylesheet load failures 2025-04-28 03:46:53 +02:00
Patrick Goldinger
e366c94d55 Rework SnyggStylesheet serialization and add lenient config and pretty print 2025-04-28 03:06:10 +02:00
Patrick Goldinger
a0ffa3feb1 Rename line-clamp to text-max-lines and reorder properties 2025-04-28 00:59:45 +02:00
Patrick Goldinger
ecbf5c4e66 Add preview icon for most new values in theme editor 2025-04-28 00:34:18 +02:00
Patrick Goldinger
023645646c Finish implementing multiple property sets editor UI in theme editor 2025-04-28 00:10:47 +02:00
lm41
553251d3c1 WIP: Add propertySet editing for SnyggMultiplePropertySetsEditor values 2025-04-27 19:20:03 +02:00
Patrick Goldinger
92ce04d5d9 Implement font-style and font-weight into Snygg font rule 2025-04-27 17:09:54 +02:00
Patrick Goldinger
9930eb1bca Implement required properties into Snygg spec and serialization 2025-04-27 17:01:56 +02:00
Patrick Goldinger
47b2d81f72 Implement Snygg multiple property sets functionality into spec 2025-04-27 16:18:22 +02:00
Patrick Goldinger
e6d6260d72 Implement file selector for Snygg URI values in theme editor
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-04-27 02:32:55 +02:00
Patrick Goldinger
dd02948a00 Improve Snygg image support and rename object-fit to content-scale 2025-04-27 01:22:22 +02:00
Patrick Goldinger
4a12b3ded0 Improve SnyggAssetResolver interface and param type 2025-04-26 04:51:02 +02:00
Patrick Goldinger
6acfa7f349 Implement basic ext editor file management
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-04-26 04:27:16 +02:00
Patrick Goldinger
d3e2dda165 Improve Snygg asset handling and robustness 2025-04-26 04:26:49 +02:00
Patrick Goldinger
a5ec6a10b3 Fix issues with meta / rule decl in Snygg 2025-04-25 22:12:57 +02:00
Patrick Goldinger
0a8260b7fa Add support for title/description in Snygg spec & Upgrade to 2020-12 schema version 2025-04-25 17:40:02 +02:00
Patrick Goldinger
4cddc9b305 Add background image support for IME surface
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-25 03:31:58 +02:00
lm41
b4835b869a Add padding value input in theme editor
Co-authored-by: Patrick Goldinger <patrick@patrickgold.dev>
2025-04-25 00:16:10 +02:00
Patrick Goldinger
11c6dc8a0d Continue adaption of base styles & Fix inherit behavior bug in Snygg 2025-04-24 18:07:53 +02:00
Patrick Goldinger
71a2baf402 Adapt app module to new SnyggRule attribute behavior 2025-04-24 16:49:59 +02:00
Patrick Goldinger
94bfd39a9b Change SnyggRule attributes to use strings as the base type 2025-04-24 16:35:07 +02:00
Patrick Goldinger
d473343ca3 Rework Snygg UI element name and adapt TextKeyboardLayout.kt 2025-04-24 02:43:15 +02:00
Patrick Goldinger
5101db7169 Implement line clamp and uri value in the theme editor 2025-04-24 01:52:59 +02:00
Patrick Goldinger
08e10639d1 Implement new Snygg enum like properties in the theme editor 2025-04-24 00:40:25 +02:00
Patrick Goldinger
741dd82003 Adapt the theme editor to use new color representation 2025-04-23 21:28:22 +02:00
Patrick Goldinger
4c2bfc5dab Add new Snygg names translations 2025-04-23 20:53:54 +02:00
lm41
ce3cb4427a Migrate ThemeEditor to Material 3 2025-04-23 16:57:26 +02:00
Patrick Goldinger
463e3a3588 Move Snygg attributes to SnyggAttributes data class 2025-04-23 16:49:03 +02:00
Patrick Goldinger
da611d3077 Document and test SnyggRule 2025-04-23 16:12:49 +02:00
Patrick Goldinger
d0afe023a6 Basic adaption of default theme files
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-23 03:38:07 +02:00
Patrick Goldinger
00f01b59db Fix ThemeManager new Snygg v2 integration
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-04-23 03:06:54 +02:00
Patrick Goldinger
7a1cc211f3 Adapt EditPropertyDialog to Snygg v2
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-23 02:26:06 +02:00
Patrick Goldinger
1e29204d9c Adapt EditRuleDialog in theme editor to Snygg v2
Co-authored-by: Lars Mühlbauer <lm41@lm41.xyz>
2025-04-23 00:52:14 +02:00
Patrick Goldinger
d541eed655 Fix tooltip showing on all usages of quick button 2025-04-10 17:31:31 +02:00
lm41
aaf7e62ed9 Switch to new Tooltip composable 2025-04-10 16:04:37 +02:00
Patrick Goldinger
29cbc4f373 Remove icon button with padding 2025-04-06 17:02:15 +02:00
Patrick Goldinger
791f3d2a69 Basic fix for emoji palette view 2025-04-06 16:46:58 +02:00
Patrick Goldinger
6595aa4d1a Fix clipboard input layout style 2025-04-06 16:28:10 +02:00
Patrick Goldinger
815ea0845a Remove SnyggSurface & Fix text input style 2025-04-06 14:45:56 +02:00
Patrick Goldinger
37c5256769 Fix and adapt base style for actions and actions editor 2025-04-06 13:55:14 +02:00
Patrick Goldinger
b85703db36 Clean up Snygg UI helpers and fix clip issues 2025-04-06 12:56:47 +02:00
Patrick Goldinger
bc1bc8fece Add Snygg line-clamp property 2025-04-05 18:12:56 +02:00
Patrick Goldinger
b3c6589326 WIP: IME UI draws again with base style 2025-04-05 17:37:07 +02:00
Patrick Goldinger
8f44d04a6f WIP: app module compiles again 2025-04-05 15:55:55 +02:00
Patrick Goldinger
349758991a Add Snygg anonymous elements and further adaptions in app 2025-04-05 14:47:42 +02:00
Patrick Goldinger
fed979dec9 Add Snygg selector inheritance and merging 2025-04-04 16:16:00 +02:00
Patrick Goldinger
d6f8555bdf WIP: continue adaption of Snygg v2 2025-04-04 15:53:46 +02:00
Patrick Goldinger
5afd6bd722 Improve SnyggStylesheet and SnyggRule tests 2025-04-03 01:02:57 +02:00
Patrick Goldinger
0716420697 WIP: Further adaption of Snygg 2025-04-02 14:33:05 +02:00
Patrick Goldinger
b923a5bf65 WIP: Add SnyggIcon, SnyggIconButton, SnyggSpacer and continue adaption 2025-04-02 13:10:52 +02:00
Patrick Goldinger
3c2b2ae473 WIP: Begin adapting app module to new Snygg v2
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-02 02:59:57 +02:00
Patrick Goldinger
1e1881e6ea Raise minimum API to 26 (Android 8)
Upgrade Kotlin to 2.1.20 and also upgrade other dependencies

Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-02 02:08:59 +02:00
Patrick Goldinger
3acda3745a Add Snygg font-family to Text
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-02 01:52:43 +02:00
Patrick Goldinger
2a8c67c4f4 Fully rework SnyggSpec and parsing behavior
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-04-02 01:46:00 +02:00
Patrick Goldinger
0d572fc1ae Add preliminary support for Snygg custom fonts and images
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-28 03:20:42 +01:00
Patrick Goldinger
7810d8034c Update Snygg stylesheet.schema.json 2025-03-26 23:24:19 +01:00
Patrick Goldinger
6b9fc555f0 Add multiple text relevant Snygg properties 2025-03-26 23:15:09 +01:00
Patrick Goldinger
f352c768f4 Automate Snygg stylesheet schema generation
Additionally, rework the value spec declaration so it is serializable.
2025-03-26 19:48:41 +01:00
Patrick Goldinger
24d6667b52 Rework Snygg selectors to enum
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-26 03:25:07 +01:00
Patrick Goldinger
d29cfff7d4 Add SnyggButton and SnyggSurface
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-26 02:32:21 +01:00
Patrick Goldinger
babf58bf53 Clean up Snygg UI helpers and add row/column
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-26 01:23:27 +01:00
Patrick Goldinger
701088c842 Implement Snygg inherit behavior
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-26 00:51:35 +01:00
Patrick Goldinger
4fdbb7c235 Add Snygg font-weight and refactor appearance code 2025-03-25 22:50:44 +01:00
Patrick Goldinger
5831bd84ad Rework SnyggSpec and serialization 2025-03-25 12:14:44 +01:00
Patrick Goldinger
dd97ff09b6 Add support for margin and padding in Snygg 2025-03-25 02:56:06 +01:00
Patrick Goldinger
a5407502f3 Add support for shadowColor in Snygg 2025-03-25 02:02:09 +01:00
Patrick Goldinger
def05ef3a7 Add first preview of SnyggText 2025-03-25 01:48:50 +01:00
Patrick Goldinger
8ec03c09cc Add further SnyggTheme tests 2025-03-25 00:54:07 +01:00
Patrick Goldinger
a298687f6e Add snygg dynamic color and compilation tests
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-24 23:38:53 +01:00
Patrick Goldinger
2488614d22 Set up Snygg UI package for v2 2025-03-24 22:22:02 +01:00
Patrick Goldinger
ca8ca65533 Full rework of snygg dynamic color handling 2025-03-24 22:14:11 +01:00
lm41
8e134cc15f Move ColorPalette to :lib:color and simplify MaterialYouColor 2025-03-24 20:22:35 +01:00
lm41
17860815b6 Add SnyggShapeValueTest 2025-03-24 18:01:58 +01:00
lm41
bb502b5f8c Improve tests and code coverage in SnyggRule 2025-03-23 20:18:30 +01:00
Patrick Goldinger
0e51f25bb0 Add basic stylesheet compilation 2025-03-23 20:16:07 +01:00
Patrick Goldinger
c1e50c9684 Add SnyggRule sorting 2025-03-23 14:09:07 +01:00
Patrick Goldinger
c377cd9ed7 Add tests for SnyggSolidColorValue 2025-03-22 23:26:55 +01:00
Patrick Goldinger
1fc3b536d9 Remove kotest and sub-dependencies 2025-03-22 22:17:16 +01:00
Patrick Goldinger
ae645fa327 Improve snygg testing build config and usage 2025-03-22 22:09:27 +01:00
Patrick Goldinger
bfd20055fc Improve SnyggStylesheetEditor and add tests 2025-03-22 21:18:06 +01:00
Patrick Goldinger
15aa6a6bb3 Improve SnyggStylesheet testing 2025-03-22 20:35:09 +01:00
Patrick Goldinger
e4ef14e684 Switch lib.snygg to kotlinx.kover
(and regain my sanity, thanks Lars)
2025-03-22 18:32:16 +01:00
Patrick Goldinger
39d7ea4fc0 Add JaCoCo to lib.snygg 2025-03-22 18:17:24 +01:00
Patrick Goldinger
6d330f807a Improve snygg stylesheet testing and move size test to lib.snygg 2025-03-22 15:53:17 +01:00
Patrick Goldinger
e6bc0657f6 Rework stylesheet serialization and ass basic test 2025-03-22 15:21:59 +01:00
Patrick Goldinger
4686234ba2 Re-implement SnyggRule and WIP stylesheet/theme
Co-authored-by: lm41 <lm41@lm41.xyz>
2025-03-22 04:54:00 +01:00
lm41
57e4765ce7 Remove custom implementation of SnyggIdToValueMap
The custom List<Pair<String, Any>> implementation of SnyggIdToValueMap
is removed in favor of the typealias for MutableMap<String, Any>. This
way we can work with normal map functions and have a more optimized
data-structure for our use-case.
The SnyggIdToValueMap.new() functions are replaced by a single
snyggIdToValueMapOf() function which allocates a new MutableMap.
The getOrThrow and getOrNull functions are modified to work with the
new underling map data-structure. The add function is a direct alias
to the putAll function.
2025-03-21 18:25:05 +01:00
Patrick Goldinger
aaf26a7a4b Add TODO comments and plan new Snygg v2 API 2025-03-21 02:40:31 +01:00
Patrick Goldinger
f8f6756b84 Initial Snygg v2 draft 2025-03-21 01:25:17 +01:00
Lars Mühlbauer
35fd70ce6d Improve crash screen (#2804)
* Improve crash screen

The whole crash screen content is now scrollable
and the buttons to report or close the activity
were moved to a footer. To distinguish between
the log content and the general explanation, a
horizontal divider was added.

* Do not restart activity on orientation change
2025-03-12 00:26:12 +01:00
Lars Mühlbauer
a0ebd62f9a Add toggle for keyboard label language (#2811) 2025-03-12 00:25:58 +01:00
Lars Mühlbauer
3dacd3c2d0 Rework one-handed mode. (#2801)
* Rework one-handed mode.

The one-handed mode now remembers the position
where it was disabled and opens to this position
the next time it is activated.

* Add seperade `TOGGLE_COMPACT_LAYOUT` keycode

* Update AppPrefs.kt

* Update KeyboardScreen.kt

* Update ComputingEvaluator.kt
2025-03-11 23:02:51 +01:00
Lars Mühlbauer
c73b8dda0b Do not ignore flagTextNoSuggestions. (#2807)
Fixes: #2806
2025-03-11 20:38:01 +01:00
Lars Mühlbauer
5353a01226 Refactor Settings (#2780)
* Remove old migration rules

* Rename advanced settings to other and move incognito settings to typing

* Move clipboard suggestions to clipboard screen

* Move other to correct alphabetical location

* Optimize++
2025-03-05 00:08:24 +01:00
florisboard-bot
34f8fec2f6 Update translations from Crowdin 2025-03-04 22:39:56 +01:00
npnpatidar
7199fcdf12 Devanagari Script and Hindi Language Layout Added (#2723)
* test commit

* hi-IN popupmappings id added

* basic layout

* heart replaces with space

* code corrected

* lots of other keys added

* all characters have been added

* popmappings rearranged

* some positional change

* * and \ won't popup due to क्ष and  ज्ञ

* ओ औ code correced

* some vovels reordered

* Hindi does not capitalization concept
2025-03-04 22:27:16 +01:00
Lars Mühlbauer
8319f563b9 Add support for switching the subtype on space bar long press (#2781)
* Add initial support for switching the subtype on space bar long press

* Fix keyboard presses behind the header panel

* Fix taps behind sheet

* Extract string ressource and refactor code

* Instant select subtype

* Persist suptype change in prefs
2025-03-04 22:23:24 +01:00
Lars Mühlbauer
45efe52159 Add new screenshot generator and update fastlane images (#2787)
* Add new screenshot generator and update fastlane images

* Update featureGraphic.png to match g-play requirements
2025-03-04 21:46:54 +01:00
Lars Mühlbauer
7a286b932b Update snygg dynamic color scheme on wallpaper change (#2778)
* Update snygg dynamic color scheme on wallpaper change

* Move broadcast receiver handling to FlorisImeService and properly unregister the receiver

* Set systembar color on stylesheet change
2025-03-04 21:08:45 +01:00
Lars Mühlbauer
df3f84e96d Fix text being rendered behind the top app bar (#2758)
* Fix text being rendered behind the top app bar

This commit fixes an issue where the text was rendered
behind the top app bar in the crash dialog activity by
removing the top app bar in the style and adding a top
app bar in the layout XML.

* Fix toolbar rendering messed up in crash dialog screen

---------

Co-authored-by: Patrick Goldinger <patrick@patrickgold.dev>
2025-02-14 13:13:44 +01:00
Lars Mühlbauer
4cc2216940 Fix switching back from voice ime (#2684) (#2759)
This commit fixes an issue where the voice ime was
not possible to switch back to FlorisBoard, because
the keyboard subtype was not specified.
2025-02-14 12:23:46 +01:00
Lars Mühlbauer
21fdd31c88 Fix BottomSheetContent drawing behind system nav bar (#2757)
This commit fixes an issue where the BottomSheetContent
was drawn behind the system navigation bar. To fix this
issue, I applied the saveDrawingPadding Modifier to the
AnimatedVisibility. There was a color problem on the
system navigation bar, so I set the background color to
SheetOutOfBoundsBgColorInactive. Now the system nav bar
is colored the right way.
2025-02-14 12:20:13 +01:00
Lars Mühlbauer
53c6cb52ca Fix crash when opening clipboard history (#2756)
This Commit fixes a crash when opening the clipboard history
with a theme which does not provide a sp size for the header
or the clipboard item. The sp value is now saveTimes multiplied
with 1f.
2025-02-14 12:15:39 +01:00
Patrick Goldinger
9b12213b3e Possible fixes for all keys invisible bug (#2743)
* Fix possible race condition in extension manager init

* Fix deprecation warnings in Kotlin contracts

* Fix race condition in KeyboardManagerResources

* Add debug glide.enabled toggle
2025-02-02 22:35:25 +01:00
Patrick Goldinger
659a5062ab Merge pull request #2750 from florisboard/feat/implement-custom-material-you-color
Implement custom material you colors
2025-02-02 20:17:29 +01:00
lm41
086e5f7782 Add new JetPrefColorPicker for the keyboard accent color.
This commit introduces the new color schemes for spoofed
material you themes. The material you themes can now be
used on any android version that is supported by FlorisBoard
and not just on android 12+.
2025-02-02 19:40:04 +01:00
lm41
ae73e64cd2 Add new JetPrefColorPicker for the settings accent color. 2025-02-02 19:35:16 +01:00
lm41
9f5e8cddd5 Add :lib:color package
This package includes a set of material 3 color schemes
and a map of the corresponding colors to the color schemes.
Please visit the packages README.md for information
on how the schemes were created.
2025-02-02 19:30:39 +01:00
Lars Mühlbauer
3724495d4f Remove code duplication in setup screen (#2742)
* Remove code duplication in setup screen

* fixup! Remove code duplication in setup screen
2025-01-16 22:52:25 +01:00
Patrick Goldinger
15b5dd9e3e Fix issues with all keys invisible detection (#2737) 2025-01-13 02:07:05 +01:00
florisboard-bot
36f06e0b4b Update translations from Crowdin 2025-01-13 00:34:27 +01:00
Patrick Goldinger
eacb5259ec Merge pull request #2736 from florisboard/chore/add-copyright-templates-to-idea
Update copyright to the new copyright holders
2025-01-13 00:30:04 +01:00
Patrick Goldinger
e7a82a3123 Update README.md/LICENSE 2025-01-13 00:22:59 +01:00
Patrick Goldinger
123b3a6d39 Update copyright year and name in all source files 2025-01-13 00:05:38 +01:00
lm41
9531ad4c36 Add copyright templates for usage with android studio and intellij 2025-01-12 23:56:59 +01:00
Lars Mühlbauer
54ed179ead Fix NoSuchMethodError: removeFirst() on android 14 and lower (#2734)
* Fix NoSuchMethodError: removeFirst() on android 14 and lower

* Add RequiredApi annotations to SnyggMaterialYou classes

---------

Co-authored-by: Patrick Goldinger <patrick@patrickgold.dev>
2025-01-12 23:25:20 +01:00
Patrick Goldinger
2dc7efd811 Add better detection for all keys visible bug (#2735)
* Add better detection for all keys visible bug

* Remove on purpose fail for extension manager again
2025-01-12 23:23:38 +01:00
Lars Mühlbauer
01d0b02e6d Fix keyboard height calculation on android 15 to match previous android versions (#2722) 2025-01-11 17:31:51 +01:00
Patrick Goldinger
67c083131a Upgrade to Android 15 (#2733) 2025-01-11 17:17:35 +01:00
Lars Mühlbauer
03cde7296e Add option to delete EmojiHistory from settings screen (#2732)
* Add possibility to delete EmojiHistory from settings screen

* Apply review suggestions

* fixup! Apply review suggestions

* Fix stylistic issues
2025-01-11 16:12:23 +01:00
Lars Mühlbauer
32d26bcf80 Add subtypes and installed extensions to debug logs (#2731)
* Add subtypes and installed extensions to debug logs

* Fix debug log output

* Apply suggestion
2025-01-11 15:59:47 +01:00
Lars Mühlbauer
e61a2c6e82 Fix colors in add subtype screen and enhance subtype presets dialog (#2729) 2025-01-11 15:35:55 +01:00
Md. Rifat Hasan Jihan
ce7a97dce6 added Bengali (bn) to non-capitalization group (#2700) 2024-12-01 22:33:02 +01:00
Md. Rifat Hasan Jihan
9f17a1d36c Replace ZWNJ with ZWJ for Bengali 'র‌্য' in keyboard layout (#2696) 2024-12-01 22:32:27 +01:00
Lars Mühlbauer
a248b4f717 Fix the top message in TypingScreen (#2690) 2024-12-01 22:31:26 +01:00
Lars Mühlbauer
c470b792c1 Fix Keyboard height in one-handed mode (#2668) 2024-10-31 15:10:04 +01:00
Lars Mühlbauer
ff5cd1e7c2 Fix smartbar spacing (#2665) 2024-10-31 15:03:01 +01:00
Lars Mühlbauer
32fee44364 Auto clean sensitive clipboard items (#2659)
* Auto clean sensitive clipboard items

* Fix typo :D

* Apply review suggestions
2024-10-25 16:46:08 +02:00
Patrick Goldinger
97edc33d05 Fix NetworkUtils not detecting hostnames with digits correctly (#2660) 2024-10-25 15:16:51 +02:00
Lars Mühlbauer
a89af25eab Improve ExtensionEditScreen (#2656) 2024-10-22 22:47:20 +02:00
florisboard-bot
66340249d4 Update translations from Crowdin 2024-10-21 23:17:01 +02:00
Lars Mühlbauer
14147ca1b9 Fix migration in clipboard database (#2641)
* Fix migration in clipboard database

* Update database version

* Fix migration from version 3 to version 4
2024-10-21 23:15:24 +02:00
Patrick Goldinger
bdc740637b Fix inline autofill single icon style (#2628) (#2649) 2024-10-21 17:02:36 +02:00
Patrick Goldinger
eb20e80295 Fix state issues in TextKeyboardLayout (popups) (#2647)
* Fix state issues in TextKeyboardLayout (popups)

* Fix utility key not updating correctly (#2648)
2024-10-21 15:34:15 +02:00
516 changed files with 28311 additions and 9273 deletions

11
.dockerignore Normal file
View File

@@ -0,0 +1,11 @@
**/.*/
!.git/
**/build/
**/dist/
**/out/
**/target/
utils/
!utils/repr_build/scripts/
.env
gradlew.bat
local.properties

1
.envrc
View File

@@ -1 +0,0 @@
use_flake

View File

@@ -1,4 +1,4 @@
name: Bug Report
name: 🐛 Bug Report
description: Create a report to help FlorisBoard improve
labels:
- "bug"
@@ -62,3 +62,14 @@ body:
placeholder: e.g. 10, Stock
validations:
required: true
- type: checkboxes
id: checklist
attributes:
label: "Checklist"
options:
- label: "I made sure that there are *no existing issues* - [open](https://github.com/florisboard/florisboard/issues) or [closed](https://github.com/florisboard/florisboard/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
- label: "I have read and understood the [contribution guidelines](https://github.com/florisboard/florisboard/blob/main/CONTRIBUTING.md)."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the bug report will be dismissed otherwise."
required: true

View File

@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/florisboard/florisboard/discussions/new?category=q-a
about: Ask here if you have a question about FlorisBoard or need assistance
- name: General feedback
url: https://github.com/florisboard/florisboard/discussions/new?category=feedback
about: Give general feedback about this project
- name: 💬 Matrix
url: https://matrix.to/#/#florisboard:matrix.org
about: General chat about FlorisBoard and quick Q/A
- name: ❓ Questions / Feedback
url: https://github.com/florisboard/florisboard/discussions/new/choose
about: Post your questions or feedback in the discussions panel

View File

@@ -1,4 +1,4 @@
name: Crash report
name: 💥 Crash report
description: Create a report with a generated crash log attached to help FlorisBoard improve
labels:
- "bug"
@@ -36,3 +36,14 @@ body:
description: Paste the generated crash log below
validations:
required: true
- type: checkboxes
id: checklist
attributes:
label: "Checklist"
options:
- label: "I made sure that there are *no existing issues* - [open](https://github.com/florisboard/florisboard/issues) or [closed](https://github.com/florisboard/florisboard/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
- label: "I have read and understood the [contribution guidelines](https://github.com/florisboard/florisboard/blob/main/CONTRIBUTING.md)."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the crash report will be dismissed otherwise."
required: true

View File

@@ -1,4 +1,4 @@
name: Feature request / Suggestion
name: Feature request
description: Suggest an idea for this project
labels:
- "proposal"
@@ -20,3 +20,14 @@ body:
description: Please explain your idea in a precise way.
validations:
required: true
- type: checkboxes
id: checklist
attributes:
label: "Checklist"
options:
- label: "I made sure that there are *no existing issues* - [open](https://github.com/florisboard/florisboard/issues) or [closed](https://github.com/florisboard/florisboard/issues?q=is%3Aissue+is%3Aclosed) - which I could contribute my information to."
required: true
- label: "I have read and understood the [contribution guidelines](https://github.com/florisboard/florisboard/blob/main/CONTRIBUTING.md)."
required: true
- label: "I have taken the time to fill in all the required details. I understand that the feature request will be dismissed otherwise."
required: true

View File

@@ -25,14 +25,14 @@ jobs:
with:
submodules: recursive
- uses: gradle/actions/wrapper-validation@v3
- uses: gradle/actions/wrapper-validation@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: temurin
- name: Set up CMake and Ninja
uses: lukka/get-cmake@latest
uses: lukka/get-cmake@v4.0.2
- name: Build with Gradle
run: ./gradlew clean assembleDebug
- uses: actions/upload-artifact@v4

1
.gitignore vendored
View File

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

6
.idea/copyright/copyright.xml generated Normal file
View File

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

15
.idea/copyright/profiles_settings.xml generated Normal file
View File

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

View File

@@ -4,32 +4,34 @@ Thanks for considering contributing to FlorisBoard!
There are several ways to contribute to FlorisBoard. This document provides some general guidelines for each type of contribution.
## General contributions
The FlorisBoard community is international, as such we require all contributions, including issues, pull requests, and participation in the Matrix chat to be in English and follow the [code of conduct](https://github.com/florisboard/florisboard/blob/main/CODE_OF_CONDUCT.md). Contributions not adhering to these requirements will be dismissed. Thanks for making the FlorisBoard community an inclusive and safe space for everyone!
### Translation
## Non-code contributions
To make FlorisBoard accessible in as many languages as possible, the platform [Crowdin](https://crowdin.florisboard.patrickgold.dev) is used to crowdsource and manage translations. The list of languages in Crowdin covers a good range of languages, but feel free to send an email to [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev) to request a new language.
### Translations
To make FlorisBoard accessible in as many languages as possible, the platform [Crowdin](https://crowdin.florisboard.patrickgold.dev) is used to crowdsource and manage translations. The list of languages in Crowdin covers a good range of languages, but feel free to email [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev) to request a new language.
> [!IMPORTANT]
> This is the only source of translations - **PRs that add/update translations are not accepted.**
### Feedback
You can [give general feedback](https://github.com/florisboard/florisboard/discussions/new?category=feedback) directly here on GitHub. This is the preferred way to give feedback, as it allows not only for me to read and respond to feedback, but for everyone in this community.
### Bug reporting
This kind of contribution is the most important, as it tells where FlorisBoard has flaws and thus should be improved to maximize stability and user experience. To make this process as smooth as possible, please use the pre-made [issue template](.github/ISSUE_TEMPLATE/bug_report.md) for bug reporting. This makes it easy for us to understand what the bug is and how to solve it.
Allows us to see where FlorisBoard has flaws and should be improved to maximize stability and user experience. To make this process as smooth as possible, please use the pre-made [bug report template](https://github.com/florisboard/florisboard/issues/new?template=bug_report.yml). This makes it easy for us to understand what the bug is and how to solve it.
#### Capturing error logs
Logs are captured by FlorisBoard's crash handler, which gives you the ability to copy it to the clipboard and paste it in GitHub. This is the preferred way to capture logs.
Logs are captured by FlorisBoard's crash handler, which gives you the ability to copy it to the clipboard and paste it in the crash report [issue template](https://github.com/florisboard/florisboard/issues/new?template=crash_report.yml). This is the preferred way to capture logs.
Alternatively, you can also use ADB (Android Debug Bridge) to capture the error log. This is recommended for experienced users only.
### Feature proposals
Use the feature proposal issue template to suggest a new idea or improvement for this project.
Use the feature proposal [issue template](https://github.com/florisboard/florisboard/issues/new?template=feature_request.yml) to suggest a new idea or improvement for this project.
### Feedback
You can [give general feedback](https://github.com/florisboard/florisboard/discussions/new?category=feedback) directly here on GitHub. This is the preferred way to give feedback, as it allows not only for me to read and respond to feedback, but for everyone in this community.
## Code contributions
@@ -38,15 +40,15 @@ You are always welcome to contribute new features or work on existing issues, th
> [!NOTE]
> If you intend to implement a bigger feature please coordinate with us so we can prevent that there's a major difference in expected implementation.
If you are overwhelmed by the code don't hesistate to ask for help in the [dev chat](https://matrix.to/#/#florisboard-dev:matrix.org) or the discussions tab! Some issues are also marked as good first issue, which are easy to do tasks.
If you are overwhelmed by the code don't hesitate to ask for help in the [dev chat](https://matrix.to/#/#florisboard-dev:matrix.org) or the discussions tab! Some issues are also marked as good first issue, which are easy to do tasks.
### System requirements for development
- Desktop PC with Linux or WSL2 (Windows)
- MacOS and Windows without WSL2 probably works too however there's no official support
- At least 16GB of RAM (because of Android Studio)
- At least 16GB of RAM (because of Android Studio / IntelliJ)
- The following tools must be installed:
- Android Studio (bundles SDK and NDK)
- Android Studio (bundles SDK and NDK) or IntelliJ with Android and Compose plugin
- Java 17
- CMake 3.22+
- Clang 15+
@@ -64,34 +66,7 @@ If you want to manually build the project without Android Studio you must ensure
and Gradle should take care of every build task.
## Joining the team
If you want to join the core maintainer/moderator team on a volunteer basis and be part of this project's journey that's great to hear!
### Basic Requirements
- A passion for seeing FlorisBoard flourish
- Good English skills for team and public communication
- A GitHub account and a Matrix handle
### Why Join
You'll have the chance to work directly with me and other team members. While the general idea is for us to work on all kinds of different aspects of the project as a team, if you're particularly interested in a specific area (e.g., UI, extensions, text processing), that's totally okay too!
### Available Roles
Currently the following roles are available and need help:
Role Description | Required Dev Experience
---|---
Software Developer (Kotlin) for Core App | Java/Kotlin development experience (on Android)
Software Developer (Rust) for Native Core | Some Rust development experience
GitHub Issues/Discussions Moderator | None
Crowdin Translation Verifier | Language proficiency for the language you want to verify
Interested? Feel free to dm me ([@patrickgold](https://matrix.to/#/@patrickgold:matrix.org)) on Matrix or send an email to [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev).
## Donating
Alternatively you can also show your support by buying me a coffee, so I can stay up all night and chase away bugs or add new cool stuff :)
You can also show your support by buying me a coffee, so I can stay up all night and chase away bugs or add new cool stuff :)
See the `Sponsors` button for available options!

View File

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

View File

@@ -64,7 +64,7 @@ fully respecting your privacy. Currently in early-beta state.
</tr>
</table>
Beginning with v0.6.0 FlorisBoard will enter the public beta on Google Play.
Beginning with v0.7 FlorisBoard will enter the public beta on Google Play.
## Highlighted features
- Integrated clipboard manager / history
@@ -74,7 +74,7 @@ Beginning with v0.6.0 FlorisBoard will enter the public beta on Google Play.
> [!IMPORTANT]
> Word suggestions/spell checking are not included in the current releases
> and are a major goal for the v0.5 milestone.
> and are a major goal for the v0.6 milestone.
Feature roadmap: See [ROADMAP.md](ROADMAP.md)
@@ -114,7 +114,7 @@ Many thanks to [Nikolay Anzarov](https://www.behance.net/nikolayanzarov) ([@Bloo
## License
```
Copyright 2020-2024 Patrick Goldinger
Copyright 2020-2025 The FlorisBoard Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -129,6 +129,8 @@ See the License for the specific language governing permissions and
limitations under the License.
```
Thanks to [The FlorisBoard Contributors](https://github.com/florisboard/florisboard/graphs/contributors) for making this project possible!
<!-- BEGIN SECTION: obtainium_links -->
<!-- auto-generated link templates, do NOT edit by hand -->
<!-- see fastlane/update-readme.sh -->

View File

@@ -1,44 +1,63 @@
# Roadmap
This feature roadmap intents to provide transparency to what is planned to be added to FlorisBoard in the foreseeable future. Note that there are no ETAs for any version milestones down below, experience has shown these won't hold anyways.
This feature roadmap intents to provide transparency to what is planned to be added to FlorisBoard in the foreseeable future. Note that there are no ETAs for any version milestones down below, experience has shown these won't hold anyway.
Each major milestone has associated alpha/beta releases, so if you are interested in previewing features quicker, keep an eye out! Each major 0.x release has also patch releases after the initial major release, which will be published on both the stable and preview tracks.
## 0.5
## 0.5 (currently in development)
- Implement predictive text support / spell checking
- Consider adding proximity-based key typo detection
- Add new extension type: Language Pack
- Basically groups all locale-relevant data (predictive base model, emoji suggestion data, ...)
in a dynamically importable extension file
- New text processing logic (maybe moved back / split to 0.6)
- Add floating keyboard mode
- New keyboard layout engine + file syntax based on the upcoming Unicode Keyboard v3 standard
- Add Tablet mode / Optimizations for landscape input based on new keyboard layout engine
- Add support for any remaining new features introduced with Android 13
> [!NOTE]
> The milestone 0.5 was split, thus the word suggestions now come with version 0.6. The old version 0.6 has been moved down and is now 0.7. The time it takes to implement word suggestions will not change, but we can now release the new theme editor earlier, which would otherwise lie dormant.
- [ ] Theme rework part II / Snygg v2
- [x] See https://github.com/florisboard/florisboard/pull/2855
- [x] Spaces in URI bug (See https://github.com/florisboard/florisboard/issues/2898)
- [ ] Rework cache manager (See https://github.com/florisboard/florisboard/issues/2870)
- [x] Re-add time based theme switching (See https://github.com/florisboard/florisboard/pull/2977)
- [ ] Add support for any remaining new features introduced with Android 13 / 14
- [ ] Proper physical keyboard support (See https://github.com/florisboard/florisboard/issues/2815)
- [x] Raise minimum required Android version from Android 7 (SDK level 24) to Android 8 (SDK level 26)
## 0.6
- Complete rework of the Emoji panel
- Emoji search
- Fully scrollable emoji list (soft category borders)
- More granular themeing options
- Layout customization (e.g. placement of category buttons)
- Maybe: consider upgrading to emoji2 for better unified system-wide emoji styles
- Reimplementation of glide typing with the new layout engine and predictive text core
- Prepare FlorisBoard repository and app store presence for public beta release on Google Play (will go live with stable 0.6)
- Rework branding images and texts of FlorisBoard for the app stores
- Focus on stability and experience improvements of the app and keyboard
- Add support for new features introduced with Android 14 / 15
- Not finalized, but planned: raise minimum required Android version from Android 7 (SDK level 24) to Android 8 (SDK level 26)
- [ ] Implement predictive text support / spell checking
- [ ] Add new extension type: Language Pack
- Basically groups all locale-relevant data (predictive base model, emoji suggestion data, ...)
in a dynamically importable extension file
## k3lp
> [!NOTE]
> The development of k3lp is not tied to a florisboard version and takes place on [codeberg.org](https://codeberg.org/k3lp/k3lp) simultaneously.
- [ ] New keyboard layout engine + file syntax based on the upcoming Unicode Keyboard v3 standard
- [ ] Add Tablet mode / Optimizations for landscape input based on new keyboard layout engine
## 0.7+
> [!NOTE]
> From 0.6 onwards we plan to have more stable 0.X releases but with at most one large feature per release, thus having a much quicker iteration of new features on the stable track, which is a benefit for everyone involved.
- [ ] Add floating keyboard mode
- [ ] New text processing logic
- [ ] Complete rework of the Emoji panel
- [ ] Emoji search
- [ ] Fully scrollable emoji list (soft category borders)
- [ ] Side scrollable emoji list (swipe for next category)
- [ ] More granular theming options
- [ ] Layout customization (e.g. placement of category buttons)
- [ ] Maybe: consider upgrading to emoji2 for better unified system-wide emoji styles
- [ ] Reimplementation of glide typing with the new layout engine and predictive text core
- [ ] Prepare FlorisBoard repository and app store presence for public beta release on Google Play (will go live with stable 0.7)
- [ ] Rework branding images and texts of FlorisBoard for the app stores
- [ ] Focus on stability and experience improvements of the app and keyboard
- [ ] Add support for new features introduced with Android 15 / 16
## Backlog / Planned (unassigned)
**Features that MAY be added (even in versions mentioned above) or dismissed**
- 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
- Voice-to-text with Mozilla's open-source voice service (or any other oss voice provider)
- Text translation
- Stickers/GIFs

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Patrick Goldinger
* Copyright (C) 2022-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeFeatureFlag
import java.io.ByteArrayOutputStream
plugins {
@@ -23,35 +22,39 @@ plugins {
alias(libs.plugins.kotlin.plugin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)
alias(libs.plugins.mannodermaus.android.junit5)
alias(libs.plugins.mikepenz.aboutlibraries)
}
val projectMinSdk: String by project
val projectTargetSdk: String by project
val projectCompileSdk: String by project
val projectBuildToolsVersion: String by project
val projectNdkVersion: String by project
val projectVersionCode: String by project
val projectVersionName: String by project
val projectVersionNameSuffix = projectVersionName.substringAfter("-", "")
val projectVersionNameSuffix = projectVersionName.substringAfter("-", "").let { suffix ->
if (suffix.isNotEmpty()) {
"-$suffix"
} else {
suffix
}
}
android {
namespace = "dev.patrickgold.florisboard"
compileSdk = projectCompileSdk.toInt()
buildToolsVersion = projectBuildToolsVersion
ndkVersion = projectNdkVersion
buildToolsVersion = tools.versions.buildTools.get()
ndkVersion = tools.versions.ndk.get()
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "11"
freeCompilerArgs = listOf(
"-opt-in=kotlin.contracts.ExperimentalContracts",
"-Xjvm-default=all-compatibility",
"-Xwhen-guards",
)
}
@@ -149,7 +152,13 @@ android {
}
aboutLibraries {
configPath = "app/src/main/config"
collect {
configPath = file("src/main/config")
}
}
lint {
baseline = file("lint.xml")
}
testOptions {
@@ -162,21 +171,21 @@ android {
}
}
composeCompiler {
// DO NOT ENABLE STRONG SKIPPING! This project currently relies on
// recomposition on parent state change to update the UI correctly.
featureFlags.add(ComposeFeatureFlag.StrongSkipping.disabled())
}
tasks.withType<Test> {
useJUnitPlatform()
}
dependencies {
val composeBom = platform(libs.androidx.compose.bom)
implementation(composeBom)
// testImplementation(composeBom)
// androidTestImplementation(composeBom)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.activity.ktx)
implementation(libs.androidx.autofill)
implementation(libs.androidx.collection.ktx)
implementation(libs.androidx.compose.material.icons)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.runtime.livedata)
implementation(libs.androidx.compose.ui)
@@ -186,7 +195,6 @@ dependencies {
implementation(libs.androidx.emoji2)
implementation(libs.androidx.emoji2.views)
implementation(libs.androidx.exifinterface)
implementation(libs.androidx.material.icons)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.profileinstaller)
ksp(libs.androidx.room.compiler)
@@ -202,16 +210,12 @@ dependencies {
implementation(libs.patrickgold.jetpref.material.ui)
implementation(project(":lib:android"))
implementation(project(":lib:color"))
implementation(project(":lib:kotlin"))
implementation(project(":lib:native"))
implementation(project(":lib:snygg"))
testImplementation(libs.equalsverifier)
testImplementation(libs.kotest.assertions.core)
testImplementation(libs.kotest.extensions.roboelectric)
testImplementation(libs.kotest.property)
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotlin.test.junit5)
androidTestImplementation(libs.androidx.test.ext)
androidTestImplementation(libs.androidx.test.espresso.core)
}

View File

@@ -1,3 +1,3 @@
<lint>
<issue id="UsingMaterialAndMaterial3Libraries" severity="ignore" />
<issue id="ExtraTranslation" severity="warning"/>
</lint>

View File

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

View File

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

View File

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

View File

@@ -1,18 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020-2022 Patrick Goldinger
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
@@ -128,6 +114,7 @@
android:name="dev.patrickgold.florisboard.lib.crashutility.CrashDialogActivity"
android:icon="@mipmap/floris_app_icon"
android:label="@string/crash_dialog__title"
android:configChanges="orientation|screenSize"
android:theme="@style/CrashDialogTheme"/>
<!-- Copy to Clipboard Activity -->

View File

@@ -17,6 +17,13 @@
"direction": "rtl",
"modifier": "org.florisboard.layouts:arabic"
},
{
"id": "armenian_alt_phonetic",
"label": "Armenian Alt Phonetic",
"authors": [ "MikayelB" ],
"direction": "ltr",
"modifier": "org.florisboard.layouts:armenian"
},
{
"id": "western_armenian",
"label": "Armenian (Western)",
@@ -49,6 +56,12 @@
"authors": [ "iamrasel" ],
"direction": "ltr"
},
{
"id": "hindi_in",
"label": "हिंदी",
"authors": [ "npnpatidar" ],
"direction": "ltr"
},
{
"id": "bepo",
"label": "BÉPO",

View File

@@ -0,0 +1,42 @@
[
[
{ "$": "case_selector", "lower": { "code": 2335, "label": "ट" }, "upper": { "code": 2336, "label": "ठ" } },
{ "$": "case_selector", "lower": { "code": 2337, "label": "ड" }, "upper": { "code": 2338, "label": "ढ" } },
{ "$": "case_selector", "lower": { "code": 2375, "label": "े" }, "upper": { "code": 2376, "label": "ै" } },
{ "$": "case_selector", "lower": { "code": 2352, "label": "र" }, "upper": { "code": 2371, "label": "ृ" } },
{ "$": "case_selector", "lower": { "code": 2340, "label": "त" }, "upper": { "code": 2341, "label": "थ" } },
{ "$": "case_selector", "lower": { "code": 2351, "label": "य" }, "upper": { "code": 2399, "label": "य़" } },
{ "$": "case_selector", "lower": { "code": 2369, "label": "ु" }, "upper": { "code": 2370, "label": "ू" } },
{ "$": "case_selector", "lower": { "code": 2367, "label": "ि" }, "upper": { "code": 2368, "label": "ी" } },
{ "$": "case_selector", "lower": { "code": 2379, "label": "ो" }, "upper": { "code": 2380, "label": "ौ" } },
{ "$": "case_selector", "lower": { "code": 2346, "label": "प" }, "upper": { "code": 2398, "label": "फ़" } }
],
[
{ "$": "case_selector", "lower": { "code": 2366, "label": "ा" }, "upper": { "code": 2309, "label": "अ" } },
{ "$": "case_selector", "lower": { "code": 2360, "label": "स" }, "upper": { "code": 2358, "label": "श" } },
{ "$": "case_selector", "lower": { "code": 2342, "label": "द" }, "upper": { "code": 2343, "label": "ध" } },
{ "$": "case_selector", "lower": { "code": 2347, "label": "फ" }, "upper": { "code": 2364, "label": " ़" } },
{ "$": "case_selector", "lower": { "code": 2327, "label": "ग" }, "upper": { "code": 2328, "label": "घ" } },
{ "$": "case_selector", "lower": { "code": 2361, "label": "ह" }, "upper": { "code": 2307, "label": "" } },
{ "$": "case_selector", "lower": { "code": 2332, "label": "ज" }, "upper": { "code": 2333, "label": "झ" } },
{ "$": "case_selector", "lower": { "code": 2325, "label": "क" }, "upper": { "code": 2326, "label": "ख" } },
{ "$": "case_selector", "lower": { "code": 2354, "label": "ल" }, "upper": { "code": 2355, "label": "ळ" } }
],
[
{
"$": "case_selector",
"lower": { "$": "multi_text_key", "codePoints": [2332, 2381, 2334], "label": "ज्ञ" },
"upper": { "code": 2395, "label": "ज़" }
},
{
"$": "case_selector",
"lower": { "$": "multi_text_key", "codePoints": [2325, 2381, 2359], "label": "क्ष" },
"upper": { "code": 2359, "label": "ष" }
},
{ "$": "case_selector", "lower": { "code": 2330, "label": "च" }, "upper": { "code": 2331, "label": "छ" } },
{ "$": "case_selector", "lower": { "code": 2357, "label": "व" }, "upper": { "code": 2381, "label": "्" } },
{ "$": "case_selector", "lower": { "code": 2348, "label": "ब" }, "upper": { "code": 2349, "label": "भ" } },
{ "$": "case_selector", "lower": { "code": 2344, "label": "न" }, "upper": { "code": 2339, "label": "ण" } },
{ "$": "case_selector", "lower": { "code": 2350, "label": "म" }, "upper": { "code": 2306, "label": "ं" } }
]
]

View File

@@ -3,46 +3,52 @@
{ "code": 2535, "label": "১", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 2536, "label": "২", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2537, "label": "৩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 2538, "label": "", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 2539, "label": "৫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 2540, "label": "৬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2542, "label": "৮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2543, "label": "৯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2534, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -33,7 +33,7 @@
{ "code": 32902, "label": "肆" },
{ "code": 18825, "label": "䦉" },
{ "code": 20118, "label": "亖" },
{ "code": 65300, "label": "" }
{ "code": 65300, "label": "" }
]
} },
{ "code": 20116, "label": "五", "type": "numeric", "popup": {

View File

@@ -3,46 +3,52 @@
{ "code": 2407, "label": "१", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 2408, "label": "२", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2409, "label": "३", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 2410, "label": "४", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 2411, "label": "५", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 2412, "label": "६", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2414, "label": "८", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2415, "label": "९", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2406, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 1633, "label": "١", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 1634, "label": "٢", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 1635, "label": "٣", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 1636, "label": "٤", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 1637, "label": "٥", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 1638, "label": "٦", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 1640, "label": "٨", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 1641, "label": "٩", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 1632, "label": "٠", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 2791, "label": "૧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 2792, "label": "૨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2793, "label": "૩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 2794, "label": "૪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 2795, "label": "૫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 2796, "label": "૬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2798, "label": "૮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2799, "label": "૯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2790, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 2663, "label": "", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 2664, "label": "੨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2665, "label": "੩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 2666, "label": "", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 2667, "label": "੫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 2668, "label": "੬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2670, "label": "੮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2671, "label": "੯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2662, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 3303, "label": "೧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 3304, "label": "೨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3305, "label": "೩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 3306, "label": "೪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 3307, "label": "೫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 3308, "label": "೬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3310, "label": "೮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3311, "label": "೯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3302, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 3431, "label": "൧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 3432, "label": "൨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3433, "label": "൩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 3434, "label": "൪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 3435, "label": "൫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 3436, "label": "൬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3438, "label": "൮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3439, "label": "൯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3430, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 2919, "label": "୧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 2920, "label": "", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 2921, "label": "୩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 2922, "label": "୪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 2923, "label": "୫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 2924, "label": "୬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 2926, "label": "୮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 2927, "label": "୯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 2918, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 1777, "label": "۱", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 1778, "label": "۲", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 1779, "label": "۳", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 1780, "label": "۴", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 1781, "label": "۵", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 1782, "label": "۶", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 1784, "label": "۸", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 1785, "label": "۹", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 1776, "label": "۰", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 3047, "label": "௧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 3048, "label": "௨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3049, "label": "௩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 3050, "label": "௪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 3051, "label": "௫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 3052, "label": "௬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3054, "label": "௮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3055, "label": "௯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3046, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 3175, "label": "౧", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 3176, "label": "౨", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 3177, "label": "౩", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 3178, "label": "౪", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 3179, "label": "౫", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 3180, "label": "౬", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 3182, "label": "౮", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 3183, "label": "౯", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 3174, "label": "", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,20 +3,23 @@
{ "code": 3665, "label": "๑", "type": "numeric", "popup": {
"main": { "code": 185, "label": "¹" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 3666, "label": "๒", "type": "numeric", "popup": {
"main": { "code": 178, "label": "²" },
"relevant": [
{ "code": 8322, "label": "₂"},
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
@@ -24,44 +27,59 @@
{ "code": 3667, "label": "๓", "type": "numeric", "popup": {
"main": { "code": 179, "label": "³" },
"relevant": [
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "" },
{ "code": 8323, "label": "₃"},
{ "code": 190, "label": "¾" },
{ "code": 8540, "label": "" }
{ "code": 8535, "label": "" }
]
} },
{ "code": 3668, "label": "๔", "type": "numeric", "popup": {
"main": { "code": 8308, "label": "⁴" },
"relevant": [
{ "code": 8324, "label": "₄" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 3669, "label": "๕", "type": "numeric", "popup": {
"main": { "code": 8309, "label": "⁵" },
"relevant": [
{ "code": 8325, "label": "₅" },
{ "code": 8538, "label": "⅚" },
{ "code": 8541, "label": "⅝" }
]
} },
{ "code": 3670, "label": "๖", "type": "numeric", "popup": {
"main": { "code": 8310, "label": "⁶" }
"main": { "code": 8310, "label": "⁶" },
"relevant": [
{ "code": 8326, "label": "₆" }
]
} },
{ "code": 3671, "label": "๗", "type": "numeric", "popup": {
"main": { "code": 8311, "label": "⁷" },
"relevant": [
{ "code": 8327, "label": "₇" },
{ "code": 8542, "label": "⅞" }
]
} },
{ "code": 3672, "label": "๘", "type": "numeric", "popup": {
"main": { "code": 8312, "label": "⁸" }
"main": { "code": 8312, "label": "⁸" },
"relevant": [
{ "code": 8328, "label": "₈" }
]
} },
{ "code": 3673, "label": "๙", "type": "numeric", "popup": {
"main": { "code": 8313, "label": "⁹" }
"main": { "code": 8313, "label": "⁹" },
"relevant": [
{ "code": 8329, "label": "₉" }
]
} },
{ "code": 3664, "label": "", "type": "numeric", "popup": {
"main": { "code": 8304, "label": "⁰" },
"relevant": [
{ "code": 8709, "label": "∅" },
{ "code": 8319, "label": "ⁿ" }
{ "code": 8319, "label": "ⁿ" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -3,46 +3,52 @@
{ "code": 71905, "label": "𑣡", "type": "numeric", "popup": {
"main": { "code": 49, "label": "1" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 185, "label": "¹" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
} },
{ "code": 71906, "label": "𑣢", "type": "numeric", "popup": {
"main": { "code": 50, "label": "2" },
"relevant": [
{ "code": 8532, "label": "" },
{ "code": 8322, "label": ""},
{ "code": 178, "label": "²" },
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
} },
{ "code": 71907, "label": "𑣣", "type": "numeric", "popup": {
"main": { "code": 51, "label": "3" },
"relevant": [
{ "code": 8535, "label": "⅗" },
{ "code": 190, "label": "¾" },
{ "code": 179, "label": "³" },
{ "code": 8540, "label": "⅜" }
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "⅜" },
{ "code": 8323, "label": "₃"},
{ "code": 179, "label": "³" }
]
} },
{ "code": 71908, "label": "𑣤", "type": "numeric", "popup": {
"main": { "code": 52, "label": "4" },
"relevant": [
{ "code": 8536, "label": "" },
{ "code": 8308, "label": "⁴" }
{ "code": 8324, "label": "" },
{ "code": 8308, "label": "⁴" },
{ "code": 8536, "label": "⅘" }
]
} },
{ "code": 71909, "label": "𑣥", "type": "numeric", "popup": {
"main": { "code": 53, "label": "5" },
"relevant": [
{ "code": 8538, "label": "⅚" },
{ "code": 8325, "label": "₅" },
{ "code": 8309, "label": "⁵" },
{ "code": 8541, "label": "⅝" }
]
@@ -50,6 +56,7 @@
{ "code": 71910, "label": "𑣦", "type": "numeric", "popup": {
"main": { "code": 54, "label": "6" },
"relevant": [
{ "code": 8326, "label": "₆" },
{ "code": 8310, "label": "⁶" }
]
} },
@@ -57,27 +64,32 @@
"main": { "code": 55, "label": "7" },
"relevant": [
{ "code": 8542, "label": "⅞" },
{ "code": 8327, "label": "₇" },
{ "code": 8311, "label": "⁷" }
]
} },
{ "code": 71912, "label": "𑣨", "type": "numeric", "popup": {
"main": { "code": 56, "label": "8" },
"relevant": [
{ "code": 8328, "label": "₈" },
{ "code": 8312, "label": "⁸" }
]
} },
{ "code": 71913, "label": "𑣩", "type": "numeric", "popup": {
"main": { "code": 57, "label": "9" },
"relevant": [
{ "code": 8329, "label": "₉" },
{ "code": 8313, "label": "⁹" }
]
} },
{ "code": 71904, "label": "𑣠", "type": "numeric", "popup": {
"main": { "code": 48, "label": "0" },
"relevant": [
{ "code": 8319, "label": "ⁿ" },
{ "code": 8709, "label": "∅" },
{ "code": 8304, "label": "" }
{ "code": 8319, "label": "" },
{ "code": 8304, "label": "⁰" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
} }
]

View File

@@ -10,15 +10,17 @@
"code": 49, "label": "1", "type": "numeric", "popup": {
"main": { "code": 185, "label": "¹" },
"relevant": [
{ "code": 8537, "label": "" },
{ "code": 8321, "label": "" },
{ "code": 8528, "label": "⅐" },
{ "code": 8539, "label": "⅛" },
{ "code": 8529, "label": "⅑" },
{ "code": 8530, "label": "⅒" },
{ "code": 8543, "label": "⅟" },
{ "code": 189, "label": "½" },
{ "code": 8531, "label": "⅓" },
{ "code": 188, "label": "¼" },
{ "code": 8533, "label": "⅕" }
{ "code": 8533, "label": "⅕" },
{ "code": 8537, "label": "⅙" }
]
}
}
@@ -29,6 +31,7 @@
"code": 50, "label": "2", "type": "numeric", "popup": {
"main": { "code": 178, "label": "²" },
"relevant": [
{ "code": 8322, "label": "₂"},
{ "code": 8532, "label": "⅔" },
{ "code": 8534, "label": "⅖" }
]
@@ -45,9 +48,10 @@
"code": 51, "label": "3", "type": "numeric", "popup": {
"main": { "code": 179, "label": "³" },
"relevant": [
{ "code": 8535, "label": "" },
{ "code": 8540, "label": "" },
{ "code": 8323, "label": "₃"},
{ "code": 190, "label": "¾" },
{ "code": 8540, "label": "" }
{ "code": 8535, "label": "" }
]
}
}
@@ -68,6 +72,7 @@
"code": 52, "label": "4", "type": "numeric", "popup": {
"main": { "code": 8308, "label": "⁴" },
"relevant": [
{ "code": 8324, "label": "₄" },
{ "code": 8536, "label": "⅘" }
]
}
@@ -86,6 +91,7 @@
"code": 53, "label": "5", "type": "numeric", "popup": {
"main": { "code": 8309, "label": "⁵" },
"relevant": [
{ "code": 8325, "label": "₅" },
{ "code": 8538, "label": "⅚" },
{ "code": 8541, "label": "⅝" }
]
@@ -105,7 +111,10 @@
},
"default": {
"code": 54, "label": "6", "type": "numeric", "popup": {
"main": { "code": 8310, "label": "⁶" }
"main": { "code": 8310, "label": "⁶" },
"relevant": [
{ "code": 8326, "label": "₆" }
]
}
}
},
@@ -115,6 +124,7 @@
"code": 55, "label": "7", "type": "numeric", "popup": {
"main": { "code": 8311, "label": "⁷" },
"relevant": [
{ "code": 8327, "label": "₇" },
{ "code": 8542, "label": "⅞" }
]
}
@@ -132,7 +142,10 @@
},
"default": {
"code": 56, "label": "8", "type": "numeric", "popup": {
"main": { "code": 8312, "label": "⁸" }
"main": { "code": 8312, "label": "⁸" },
"relevant": [
{ "code": 8328, "label": "₈" }
]
}
}
},
@@ -160,7 +173,10 @@
},
"default": {
"code": 57, "label": "9", "type": "numeric", "popup": {
"main": { "code": 8313, "label": "⁹" }
"main": { "code": 8313, "label": "⁹" },
"relevant": [
{ "code": 8329, "label": "₉" }
]
}
}
},
@@ -191,7 +207,9 @@
"main": { "code": 8304, "label": "⁰" },
"relevant": [
{ "code": 8709, "label": "∅" },
{ "code": 8319, "label": "ⁿ" }
{ "code": 8319, "label": "ⁿ" },
{ "code": 8585, "label": "↉" },
{ "code": 8320, "label": "₀" }
]
}
}

View File

@@ -48,6 +48,7 @@
{ "id": "fi", "authors": [ "patrickgold" ] },
{ "id": "fo", "authors": [ "BinFlush" ] },
{ "id": "fr", "authors": [ "patrickgold" ] },
{ "id": "hi-IN", "authors": [ "npnpatidar" ] },
{ "id": "hr", "authors": [ "hedidnothingwrong" ] },
{ "id": "hu", "authors": [ "zoli111, gabik65" ] },
{ "id": "hy", "authors": [ "PJTSearch" ] },
@@ -400,6 +401,16 @@
"characters": "org.florisboard.layouts:qwertz"
}
},
{
"languageTag": "hy",
"composer": "org.florisboard.composers:appender",
"currencySet": "org.florisboard.currencysets:armenian_dram",
"popupMapping": "org.florisboard.localization:hy",
"preferred": {
"characters": "org.florisboard.layouts:armenian_alt_phonetic",
"symbols": "org.florisboard.layouts:armenian"
}
},
{
"languageTag": "hy",
"composer": "org.florisboard.composers:appender",
@@ -695,6 +706,16 @@
"numericAdvanced": "org.florisboard.layouts:bengali"
}
},
{
"languageTag": "hi-IN",
"composer": "org.florisboard.composers:appender",
"currencySet": "org.florisboard.currencysets:indian_rupee",
"popupMapping": "org.florisboard.localization:hi-IN",
"preferred": {
"characters": "org.florisboard.layouts:hindi_in",
"numericRow": "org.florisboard.layouts:devanagari"
}
},
{
"languageTag": "ast",
"composer": "org.florisboard.composers:appender",

View File

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

View File

@@ -0,0 +1,173 @@
{
"all": {
"क": {
"main": { "$": "auto_text_key", "code": 2392, "label": "क़" },
"relevant": [{ "$": "auto_text_key", "code": 2393, "label": "ख़" }]
},
"ग": {
"main": { "$": "auto_text_key", "code": 2394, "label": "ग़" },
"relevant": [{ "$": "auto_text_key", "code": 2427, "label": "ॻ" }]
},
"च": {
"relevant": [
{ "$": "auto_text_key", "code": 2385, "label": " ॑" },
{ "$": "auto_text_key", "code": 2386, "label": " ॒" }
]
},
"ज": {
"main": { "$": "auto_text_key", "code": 2395, "label": "ज़" },
"relevant": [
{ "$": "auto_text_key", "code": 2428, "label": "ॼ" },
{ "$": "auto_text_key", "code": 2425, "label": "ॹ" }
]
},
"ड": {
"main": { "$": "auto_text_key", "code": 2396, "label": "ड़" },
"relevant": [{ "$": "auto_text_key", "code": 2397, "label": "ढ़" }]
},
"त": {
"main": { "$": "multi_text_key", "codePoints": [2340, 2381, 2352], "label": "त्र" }
},
"द": {
"main": { "$": "auto_text_key", "code": 2396, "label": "ड़" },
"relevant": [
{ "$": "auto_text_key", "code": 2430, "label": "ॾ" },
{ "$": "auto_text_key", "code": 2397, "label": "ढ़" },
{ "$": "auto_text_key", "code": 2424, "label": "ॸ" }
]
},
"न": {
"main": { "$": "auto_text_key", "code": 2329, "label": "ङ" },
"relevant": [
{ "$": "auto_text_key", "code": 2345, "label": "ऩ" },
{ "$": "auto_text_key", "code": 2334, "label": "ञ" }
]
},
"फ": {
"main": { "$": "auto_text_key", "code": 2398, "label": "फ़" }
},
"ब": {
"relevant": [
{ "$": "auto_text_key", "code": 2431, "label": "ॿ" },
{ "$": "auto_text_key", "code": 2365, "label": "ऽ" },
{ "$": "auto_text_key", "code": 2416, "label": "॰" }
]
},
"म": {
"main": { "$": "auto_text_key", "code": 2305, "label": "ँ" },
"relevant": [{ "$": "auto_text_key", "code": 2304, "label": "ऀ" }]
},
"य": {
"main": { "$": "auto_text_key", "code": 2426, "label": "ॺ" }
},
"र": {
"main": { "$": "auto_text_key", "code": 2315, "label": "ऋ" },
"relevant": [
{ "$": "auto_text_key", "code": 2400, "label": "ॠ" },
{ "$": "auto_text_key", "code": 2372, "label": "ॄ" },
{ "$": "auto_text_key", "code": 2353, "label": "ऱ" }
]
},
"ल": {
"relevant": [
{ "$": "auto_text_key", "code": 2402, "label": "ॢ" },
{ "$": "auto_text_key", "code": 2403, "label": "ॣ" },
{ "$": "auto_text_key", "code": 2316, "label": "ऌ" },
{ "$": "auto_text_key", "code": 2401, "label": "ॡ" },
{ "$": "auto_text_key", "code": 2356, "label": "ऴ" }
]
},
"व": {
"relevant": [
{ "$": "auto_text_key", "code": 2387, "label": " ॓" },
{ "$": "auto_text_key", "code": 2388, "label": " ॔" }
]
},
"स": {
"main": { "$": "multi_text_key", "codePoints": [2358, 2381, 2352], "label": "श्र" },
"relevant": [{ "$": "auto_text_key", "code": 2359, "label": "ष" }]
},
"ा": {
"main": { "$": "auto_text_key", "code": 2310, "label": "आ" },
"relevant": [
{ "$": "auto_text_key", "code": 2373, "label": "ॅ" },
{ "$": "auto_text_key", "code": 2418, "label": "ॲ" },
{ "$": "auto_text_key", "code": 2308, "label": "ऄ" }
]
},
"ि": {
"main": { "$": "auto_text_key", "code": 2311, "label": "इ" },
"relevant": [{ "$": "auto_text_key", "code": 2312, "label": "ई" }]
},
"ु": {
"main": { "$": "auto_text_key", "code": 2313, "label": "उ" },
"relevant": [
{ "$": "auto_text_key", "code": 2422, "label": "ॶ" },
{ "$": "auto_text_key", "code": 2423, "label": "ॷ" },
{ "$": "auto_text_key", "code": 2390, "label": " ॖ" },
{ "$": "auto_text_key", "code": 2314, "label": "ऊ" },
{ "$": "auto_text_key", "code": 2391, "label": " ॗ" }
]
},
"े": {
"main": { "$": "auto_text_key", "code": 2319, "label": "ए" },
"relevant": [
{ "$": "auto_text_key", "code": 2317, "label": "ऍ" },
{ "$": "auto_text_key", "code": 2318, "label": "ऎ" },
{ "$": "auto_text_key", "code": 2374, "label": " ॆ" },
{ "$": "auto_text_key", "code": 2320, "label": "ऐ" },
{ "$": "auto_text_key", "code": 2382, "label": " ॎ" },
{ "$": "auto_text_key", "code": 2389, "label": " ॕ" }
]
},
"ो": {
"main": { "$": "auto_text_key", "code": 2323, "label": "ओ" },
"relevant": [
{ "$": "auto_text_key", "code": 2322, "label": "ऒ" },
{ "$": "auto_text_key", "code": 2378, "label": " ॊ" },
{ "$": "auto_text_key", "code": 2383, "label": " ॏ" },
{ "$": "auto_text_key", "code": 2421, "label": "ॵ" },
{ "$": "auto_text_key", "code": 2384, "label": "ॐ" },
{ "$": "auto_text_key", "code": 2377, "label": "ॉ" },
{ "$": "auto_text_key", "code": 2419, "label": "ॳ" },
{ "$": "auto_text_key", "code": 2420, "label": "ॴ" },
{ "$": "auto_text_key", "code": 2362, "label": " ऺ" },
{ "$": "auto_text_key", "code": 2363, "label": " ऻ" },
{ "$": "auto_text_key", "code": 2324, "label": "औ" },
{ "$": "auto_text_key", "code": 2321, "label": "ऑ" }
]
},
"~right": {
"main": { "code": 2404, "label": "।" },
"relevant": [
{ "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": "(" } },
{ "$": "layout_direction_selector", "ltr": { "code": 41, "label": ")" }, "rtl": { "code": 40, "label": ")" } },
{ "code": 8205, "label": ">⁞<" },
{ "code": 8204, "label": "<⁞>" },
{ "code": 2417, "label": "ॱ" },
{ "code": 2429, "label": "" },
{ "code": 33, "label": "!" },
{ "code": 63, "label": "?" },
{ "code": 2405, "label": "॥" }
]
}
},
"uri": {
"~right": {
"main": { "code": -255, "label": ".com" },
"relevant": [
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".net" },
{ "code": -255, "label": ".in" },
{ "code": -255, "label": ".co.in" }
]
}
}
}

View File

@@ -10,9 +10,9 @@
"main": { "$": "auto_text_key" ,"code" : 237, "label": "í" }
},
"o": {
"main": { "$": "auto_text_key", "code" : 246, "label": "ö" },
"main": { "$": "auto_text_key", "code" : 243, "label": "ó" },
"relevant": [
{ "$": "auto_text_key", "code" : 243, "label": "ó" },
{ "$": "auto_text_key", "code" : 246, "label": "ö" },
{ "$": "auto_text_key", "code" : 337, "label": "ő" }
]
},
@@ -22,9 +22,9 @@
]
},
"u": {
"main": { "$": "auto_text_key", "code" : 252, "label": "ü" },
"main": { "$": "auto_text_key", "code" : 250, "label": "ú" },
"relevant": [
{ "$": "auto_text_key", "code" : 250, "label": "ú" },
{ "$": "auto_text_key", "code" : 252, "label": "ü" },
{ "$": "auto_text_key", "code" : 369, "label": "ű" }
]
},

View File

@@ -1,65 +0,0 @@
{
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
"name": "gboard_day",
"label": "Gboard Day",
"authors": [ "patrickgold", "itskareem" ],
"isNightTheme": false,
"attributes": {
"window": {
"colorPrimary": "#0479ed",
"colorPrimaryDark": "#0467c9",
"colorAccent": "#FF9800",
"navigationBarColor": "@keyboard/background",
"navigationBarLight": "true",
"semiTransparentColor": "#20000000",
"textColor": "#000000"
},
"keyboard": {
"background": "#D1D6DC"
},
"key": {
"background": "#FCFFFF",
"backgroundPressed": "#F5F5F5",
"foreground": "@window/textColor",
"foregroundPressed": "@window/textColor",
"showBorder": "true"
},
"key:enter": {
"background": "@window/colorPrimary",
"backgroundPressed": "@window/colorPrimaryDark",
"foreground": "#FFFFFF",
"foregroundPressed": "#FFFFFF"
},
"key:shift:capslock": {
"foreground": "@window/colorAccent",
"foregroundPressed": "@window/colorAccent"
},
"media": {
"foreground": "@window/textColor",
"foregroundAlt": "#757575"
},
"oneHanded": {
"background": "@keyboard/background",
"foreground": "#424242"
},
"popup": {
"background": "#EEEEEE",
"backgroundActive": "#BDBDBD",
"foreground": "@window/textColor"
},
"privateMode": {
"background": "#A000FF",
"foreground": "#FFFFFF"
},
"smartbar": {
"background": "@keyboard/background",
"foreground": "@window/textColor",
"foregroundAlt": "#8A8A8A"
},
"smartbarButton": {
"background": "@key/background",
"foreground": "@key/foreground"
},
"glideTrail": {"foreground": "#200479ed"}
}
}

View File

@@ -1,65 +0,0 @@
{
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
"name": "gboard_night",
"label": "Gboard Night",
"authors": [ "Netscaping" ],
"isNightTheme": true,
"attributes": {
"window": {
"colorPrimary": "#5e97f6",
"colorPrimaryDark": "#4285f4",
"colorAccent": "#FF9800",
"navigationBarColor": "@keyboard/background",
"navigationBarLight": "false",
"semiTransparentColor": "#20FFFFFF",
"textColor": "#FFFFFF"
},
"keyboard": {
"background": "#292e33"
},
"key": {
"background": "#484c4f",
"backgroundPressed": "#5e5e60",
"foreground": "@window/textColor",
"foregroundPressed": "@window/textColor",
"showBorder": "true"
},
"key:enter": {
"background": "@window/colorPrimary",
"backgroundPressed": "@window/colorPrimaryDark",
"foreground": "#FFFFFF",
"foregroundPressed": "#FFFFFF"
},
"key:shift:capslock": {
"foreground": "@window/colorAccent",
"foregroundPressed": "@window/colorAccent"
},
"media": {
"foreground": "@window/textColor",
"foregroundAlt": "#BDBDBD"
},
"oneHanded": {
"background": "#373c41",
"foreground": "#9b9da0"
},
"popup": {
"background": "#373c41",
"backgroundActive": "#5a5e60",
"foreground": "@window/textColor"
},
"privateMode": {
"background": "#A000FF",
"foreground": "#FFFFFF"
},
"smartbar": {
"background": "transparent",
"foreground": "#d4d5d6",
"foregroundAlt": "#73FFFFFF"
},
"smartbarButton": {
"background": "#FFFFFF",
"foreground": "#686868"
},
"glideTrail": {"foreground": "#205e97f6"}
}
}

View File

@@ -2,10 +2,10 @@
"$": "ime.extension.theme",
"meta": {
"id": "org.florisboard.themes",
"version": "0.1.0",
"version": "0.2.0",
"title": "FlorisBoard default themes",
"description": "Default themes (both day and night) for the keyboard UI",
"maintainers": [ "patrickgold <patrick@patrickgold.dev>" ],
"maintainers": [ "patrickgold <patrick@patrickgold.dev>", "lm41 <lm41@lm41.xyz>" ],
"license": "apache-2.0"
},
"themes": [
@@ -13,49 +13,37 @@
"id": "floris_day",
"label": "Floris Day",
"authors": [ "patrickgold" ],
"isNight": false,
"isBorderless": false,
"isMaterialYouAware": false
"isNight": false
},
{
"id": "floris_day_borderless",
"label": "Floris Day (Borderless)",
"authors": [ "patrickgold" ],
"isNight": false,
"isBorderless": true,
"isMaterialYouAware": false
"isNight": false
},
{
"id": "floris_night",
"label": "Floris Night",
"authors": [ "patrickgold" ],
"isNight": true,
"isBorderless": false,
"isMaterialYouAware": false
"isNight": true
},
{
"id": "floris_night_borderless",
"label": "Floris Night (Borderless)",
"authors": [ "patrickgold" ],
"isNight": true,
"isBorderless": true,
"isMaterialYouAware": false
"isNight": true
},
{
"id": "floris_pure_night",
"label": "Floris Pure Night",
"authors": [ "serebit" ],
"isNight": true,
"isBorderless": false,
"isMaterialYouAware": false
"isNight": true
},
{
"id": "floris_pure_night_borderless",
"label": "Floris Pure Night (Borderless)",
"authors": [ "serebit" ],
"isNight": true,
"isBorderless": true,
"isMaterialYouAware": false
"isNight": true
}
]
}

View File

@@ -1,23 +1,40 @@
{
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
"@defines": {
"--primary": "#4caf50",
"--primary-variant": "#388e3c",
"--secondary": "#ff9800",
"--secondary-variant": "#e65100",
"--background": "#e0e0e0",
"--background-variant": "#d0d0d0",
"--surface": "#ffffff",
"--surface-variant": "#f5f5f5",
"--popup-surface": "#eeeeee",
"--focused-popup-surface": "#bdbdbd",
"--drag-marker": "rgb(255,0,0)",
"--spacer-color": "rgba(0 ,0, 0, 0.25)",
"--one-hand-background": "#e8f5e9",
"--one-hand-foreground": "#424242",
"--incognito-icon-color": "#00000011",
"--on-primary": "#f0f0f0",
"--on-background": "#121212",
"--on-background-disabled": "rgb(175,175,175)",
"--on-surface": "#000000",
"--on-surface-variant": "#5f5f5f",
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"--shape-chip": "rounded-corner(50%, 50%, 50%, 50%)"
},
"keyboard": {
"background": "var(--background)"
"window": {
"background": "var(--background)",
"foreground": "var(--on-background)"
},
"key": {
@@ -25,170 +42,322 @@
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "1"
},
"key:pressed": {
"background": "var(--surface-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]": {
"key[code=10]": {
"background": "var(--primary)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]:pressed": {
"key[code=10]:pressed": {
"background": "var(--primary-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
"foreground": "var(--secondary)"
},
"key[code={c:space}]": {
"key[code=32]": {
"background": "var(--surface)",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp",
"text-overflow": "ellipsis"
},
"key[code=-201,-202,-203]": {
"font-size": "18sp"
},
"key[code=-204,-205]": {
"font-size": "12sp"
},
"key[code=-205]": {
"text-max-lines": "2"
},
"key[code=-11][shiftstate=`caps_lock`]": {
"foreground": "var(--secondary)"
},
"key-hint": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp"
"font-family": "monospace",
"font-size": "12sp",
"padding": "0dp 1dp 1dp 0dp",
"text-max-lines": "1"
},
"key-popup": {
"background": "#eeeeee",
"key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"key-popup:focus": {
"background": "#bdbdbd",
"foreground": "var(--on-surface)"
"key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"key-popup-extended-indicator": {
"font-size": "16sp"
},
"smartbar": {
"font-size": "18sp"
},
"smartbar-shared-actions-toggle": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "6dp",
"shape": "circle()",
"shadow-elevation": "2dp"
},
"smartbar-extended-actions-toggle": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"margin": "6dp",
"shape": "circle()"
},
"smartbar-action-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-key:disabled": {
"background": "transparent",
"foreground": "#12121248"
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-tile:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-tile:disabled": {
"background": "transparent",
"foreground": "#12121248"
"smartbar-actions-overflow": {
"margin": "4dp"
},
"smartbar-actions-overflow-customize-button": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"font-size": "14sp",
"shape": "circle()",
"shadow-elevation": "2dp"
"margin": "0dp 8dp 0dp 0dp",
"shape": "rounded-corner(24dp, 24dp, 24dp, 24dp)"
},
"smartbar-action-tile": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"font-size": "14sp",
"margin": "4dp",
"padding": "4dp",
"shape": "rounded-corner(20%, 20%, 20%, 20%)",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-action-tile:disabled": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile-icon": {
"font-size": "24sp",
"margin": "0dp 0dp 0dp 8dp"
},
"smartbar-actions-editor": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"smartbar-actions-editor-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "16sp"
"font-size": "16sp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"smartbar-actions-editor-subheader": {
"foreground": "var(--on-background)",
"font-size": "16sp"
"foreground": "var(--secondary)",
"font-size": "16sp",
"font-weight": "bold",
"padding": "12dp 16dp 12dp 8dp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile-grid": {
"margin": "4dp 0dp"
},
"smartbar-actions-editor-tile": {
"margin": "4dp",
"padding": "8dp",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile[code=-999]": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-actions-editor-tile[code=-991]": {
"foreground": "var(--drag-marker)"
},
"smartbar-candidate-word": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rectangle()"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rectangle()",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-word:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
"foreground": "var(--on-surface)"
},
"smartbar-candidate-word-secondary-text": {
"font-size": "8sp",
"margin": "0dp 2dp 0dp 0dp"
},
"smartbar-candidate-clip": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-clip:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
"foreground": "var(--on-surface)"
},
"smartbar-candidate-clip-icon": {
"margin": "0dp 0dp 4dp 0dp"
},
"smartbar-candidate-spacer": {
"foreground": "var(--surface)"
"foreground": "var(--spacer-color)"
},
"clipboard-header": {
"background": "transparent",
"foreground": "var(--on-surface)",
"foreground": "var(--on-background)",
"font-size": "16sp"
},
"clipboard-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"clipboard-header-button:disabled": {
"foreground": "var(--on-background-disabled)"
},
"clipboard-header-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"clipboard-subheader": {
"font-size": "14sp",
"margin": "6dp 10dp 6dp 6dp"
},
"clipboard-content": {
"padding": "10dp 0dp"
},
"clipboard-filter-row": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"padding": "0dp 0dp 4dp 0dp",
"shape": "var(--shape-variant)"
},
"clipboard-filter-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "4dp 4dp 0dp 4dp",
"padding": "8dp 4dp",
"shape": "var(--shape-chip)"
},
"clipboard-filter-chip[state=`active`]": {
"background": "var(--primary)",
"foreground": "var(--on-primary)"
},
"clipboard-filter-chip-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-grid": {
"shape": "var(--shape-variant)"
},
"clipboard-item": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "10",
"text-overflow": "ellipsis"
},
"clipboard-item[type=`text`]": {
"padding": "12dp 8dp"
},
"clipboard-item-description": {
"font-size": "12sp",
"font-style": "italic"
},
"clipboard-item-popup": {
"background": "var(--surface-variant)",
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
"clipboard-item-popup[type=`text`]": {
"padding": "12dp 8dp"
},
"emoji-key:pressed": {
"clipboard-item-timestamp": {
"font-size": "11sp",
"padding": "16dp 8dp"
},
"clipboard-item-actions": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"emoji-key-popup": {
"background": "#eeeeee",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-tab": {
"foreground": "var(--on-background)"
"clipboard-item-action": {
"font-size": "16sp",
"padding": "12dp"
},
"emoji-tab:focus": {
"foreground": "var(--primary)"
"clipboard-item-action-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-clear-all-dialog": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)",
"shadow-elevation": "1dp"
},
"clipboard-clear-all-dialog-message": {
"padding": "16dp"
},
"clipboard-clear-all-dialog-buttons": {
"padding": "4dp"
},
"clipboard-clear-all-dialog-button": {
"background": "transparent",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)"
},
"clipboard-history-disabled-title": {
"font-weight": "bold"
},
"clipboard-history-disabled-message": {
"padding": "0dp 4dp 0dp 8dp"
},
"clipboard-history-disabled-button": {
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"shape": "rounded-corner(24dp,24dp,24dp,24dp)"
},
"clipboard-history-locked-title": {
"font-weight": "bold",
"text-align": "center"
},
"clipboard-history-locked-message": {
"padding": "0dp 4dp 0dp 0dp",
"text-align": "center"
},
"extracted-landscape-input-layout": {
@@ -213,15 +382,82 @@
},
"incognito-mode-indicator": {
"foreground": "#00000011"
"foreground": "var(--incognito-icon-color)"
},
"inline-autofill-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-subheader": {
"font-weight": "bold",
"margin": "4dp"
},
"media-emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
},
"media-emoji-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"media-emoji-key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"media-emoji-tab": {
"foreground": "var(--on-background)"
},
"media-emoji-tab:focus": {
"foreground": "var(--primary)"
},
"media-bottom-row-button": {
"padding": "16dp 0dp",
"shape": "var(--shape)"
},
"media-emoji-key-popup-extended-indicator": {
"foreground": "inherit"
},
"one-handed-panel": {
"background": "#e8f5e9",
"foreground": "#424242"
"background": "var(--one-hand-background)",
"foreground": "var(--one-hand-foreground)"
},
"system-nav-bar": {
"background": "var(--background)"
"subtype-panel": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"subtype-panel-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "18sp",
"padding": "12dp",
"text-align": "center",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"subtype-panel-list-item": {
"font-size": "16sp",
"padding": "16dp"
},
"subtype-panel-list-item-icon-leading": {
"font-size": "24sp",
"padding": "0dp 0dp 16dp 0dp"
},
"subtype-panel-list-item-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
}
}

View File

@@ -1,83 +1,124 @@
{
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
"@defines": {
"--primary": "#4caf50",
"--primary-variant": "#388e3c",
"--secondary": "#ff9800",
"--secondary-variant": "#e65100",
"--background": "#e0e0e0",
"--background-variant": "#d0d0d0",
"--surface": "#f0f0f0",
"--surface-variant": "#ffffff",
"--popup-surface": "#eeeeee",
"--focused-popup-surface": "#bdbdbd",
"--drag-marker": "rgb(255,0,0)",
"--spacer-color": "rgba(0 ,0, 0, 0.25)",
"--one-hand-background": "#e8f5e9",
"--one-hand-foreground": "#424242",
"--incognito-icon-color": "#00000011",
"--on-primary": "#f0f0f0",
"--on-background": "#121212",
"--on-background-disabled": "#12121248",
"--on-surface": "#000000",
"--on-surface-variant": "#5f5f5f",
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"--shape-chip": "rounded-corner(50%, 50%, 50%, 50%)"
},
"keyboard": {
"background": "var(--background)"
"window": {
"background": "var(--background)",
"foreground": "var(--on-background)"
},
"key": {
"background": "transparent",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)"
"shape": "var(--shape)",
"text-max-lines": "1"
},
"key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]": {
"key[code=10]": {
"background": "var(--primary)",
"foreground": "var(--on-surface)"
"foreground": "var(--on-surface)",
"margin": "0dp 6dp"
},
"key[code={c:enter}]:pressed": {
"key[code=10]:pressed": {
"background": "var(--primary-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
"foreground": "var(--secondary)"
},
"key[code={c:space}]": {
"key[code=32]": {
"background": "var(--surface)",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp",
"margin": "0dp 6dp",
"text-overflow": "ellipsis"
},
"key[code=-201,-202,-203]": {
"font-size": "18sp"
},
"key[code=-204,-205]": {
"font-size": "12sp"
},
"key[code=-205]": {
"text-max-lines": "2"
},
"key[code=-11][shiftstate=`caps_lock`]": {
"foreground": "var(--secondary)"
},
"key-hint": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp"
"font-size": "12sp",
"font-family": "monospace",
"padding": "0dp 1dp 1dp 0dp",
"text-max-lines": "1"
},
"key-popup": {
"background": "#eeeeee",
"key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"key-popup:focus": {
"background": "#bdbdbd",
"foreground": "var(--on-surface)"
"key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape)"
},
"key-popup-extended-indicator": {
"font-size": "16sp"
},
"smartbar": {
"font-size": "18sp"
},
"smartbar-shared-actions-toggle": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "6dp",
"shape": "circle()",
"shadow-elevation": "2dp"
},
"smartbar-extended-actions-toggle": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"margin": "6dp",
"shape": "circle()"
},
"smartbar-action-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-key:pressed": {
@@ -85,109 +126,244 @@
"foreground": "var(--on-surface)"
},
"smartbar-action-key:disabled": {
"background": "transparent",
"foreground": "#12121248"
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-tile:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-tile:disabled": {
"background": "transparent",
"foreground": "#12121248"
"smartbar-actions-overflow": {
"margin": "4dp"
},
"smartbar-actions-overflow-customize-button": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"font-size": "14sp",
"shape": "circle()",
"shadow-elevation": "2dp"
"margin": "0dp 8dp 0dp 0dp",
"shape": "rounded-corner(24dp, 24dp, 24dp, 24dp)"
},
"smartbar-action-tile": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"font-size": "14sp",
"margin": "4dp",
"padding": "4dp",
"shape": "rounded-corner(20%, 20%, 20%, 20%)",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-action-tile:disabled": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile-icon": {
"font-size": "24sp",
"margin": "0dp 0dp 0dp 8dp"
},
"smartbar-actions-editor": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"smartbar-actions-editor-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "16sp"
"font-size": "16sp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"smartbar-actions-editor-subheader": {
"foreground": "var(--on-background)",
"font-size": "16sp"
"font-size": "16sp",
"font-weight": "bold",
"padding": "12dp 16dp 12dp 8dp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile-grid": {
"margin": "4dp 0dp"
},
"smartbar-actions-editor-tile": {
"margin": "4dp",
"padding": "8dp",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile[code=-999]": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-actions-editor-tile[code=-991]": {
"foreground": "var(--drag-marker)"
},
"smartbar-candidate-word": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rectangle()"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rectangle()",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-word:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
},
"smartbar-candidate-word-secondary-text": {
"font-size": "8sp",
"margin": "0dp 2dp 0dp 0dp"
},
"smartbar-candidate-clip": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-clip:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
},
"smartbar-candidate-clip-icon": {
"margin": "0dp 0dp 4dp 0dp"
},
"smartbar-candidate-spacer": {
"foreground": "var(--surface)"
},
"clipboard-header": {
"background": "transparent",
"foreground": "var(--on-surface)",
"foreground": "var(--on-background)",
"font-size": "16sp"
},
"clipboard-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"clipboard-header-button:disabled": {
"foreground": "var(--on-background-disabled)"
},
"clipboard-header-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"clipboard-subheader": {
"font-size": "14sp",
"margin": "6dp 10dp 6dp 6dp"
},
"clipboard-content": {
"padding": "10dp 0dp"
},
"clipboard-filter-row": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"padding": "0dp 0dp 4dp 0dp",
"shape": "var(--shape-variant)"
},
"clipboard-filter-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "4dp 4dp 0dp 4dp",
"padding": "8dp 4dp",
"shape": "var(--shape-chip)"
},
"clipboard-filter-chip[state=`active`]": {
"background": "var(--primary)",
"foreground": "var(--on-primary)"
},
"clipboard-filter-chip-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-grid": {
"shape": "var(--shape-variant)"
},
"clipboard-item": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "10",
"text-overflow": "ellipsis"
},
"clipboard-item[type=`text`]": {
"padding": "12dp 8dp"
},
"clipboard-item-description": {
"font-size": "12sp",
"font-style": "italic"
},
"clipboard-item-popup": {
"background": "var(--surface-variant)",
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
"clipboard-item-popup[type=`text`]": {
"padding": "12dp 8dp"
},
"emoji-key:pressed": {
"clipboard-item-timestamp": {
"font-size": "11sp",
"padding": "16dp 8dp"
},
"clipboard-item-actions": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"emoji-key-popup": {
"background": "#eeeeee",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-tab": {
"foreground": "var(--on-background)"
"clipboard-item-action": {
"font-size": "16sp",
"padding": "12dp"
},
"emoji-tab:focus": {
"foreground": "var(--primary)"
"clipboard-item-action-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-clear-all-dialog": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)",
"shadow-elevation": "1dp"
},
"clipboard-clear-all-dialog-message": {
"padding": "16dp"
},
"clipboard-clear-all-dialog-buttons": {
"padding": "4dp"
},
"clipboard-clear-all-dialog-button": {
"background": "transparent",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)"
},
"clipboard-history-disabled-title": {
"font-weight": "bold"
},
"clipboard-history-disabled-message": {
"padding": "0dp 4dp 0dp 8dp"
},
"clipboard-history-disabled-button": {
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"shape": "rounded-corner(24dp,24dp,24dp,24dp)"
},
"clipboard-history-locked-title": {
"font-weight": "bold",
"text-align": "center"
},
"clipboard-history-locked-message": {
"padding": "0dp 4dp 0dp 0dp",
"text-align": "center"
},
"extracted-landscape-input-layout": {
@@ -212,15 +388,82 @@
},
"incognito-mode-indicator": {
"foreground": "#00000011"
"foreground": "var(--incognito-icon-color)"
},
"inline-autofill-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-subheader": {
"font-weight": "bold",
"margin": "4dp"
},
"media-emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
},
"media-emoji-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"media-emoji-key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"media-emoji-tab": {
"foreground": "var(--on-background)"
},
"media-emoji-tab:focus": {
"foreground": "var(--primary)"
},
"media-bottom-row-button": {
"padding": "16dp 0dp",
"shape": "var(--shape)"
},
"media-emoji-key-popup-extended-indicator": {
"foreground": "inherit"
},
"one-handed-panel": {
"background": "#e8f5e9",
"foreground": "#424242"
"background": "var(--one-hand-background)",
"foreground": "var(--one-hand-foreground)"
},
"system-nav-bar": {
"background": "var(--background)"
"subtype-panel": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"subtype-panel-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "18sp",
"padding": "12dp",
"text-align": "center",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"subtype-panel-list-item": {
"font-size": "16sp",
"padding": "16dp"
},
"subtype-panel-list-item-icon-leading": {
"font-size": "24sp",
"padding": "0dp 0dp 16dp 0dp"
},
"subtype-panel-list-item-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
}
}

View File

@@ -1,23 +1,35 @@
{
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
"@defines": {
"--primary": "#4caf50",
"--primary-variant": "#388e3c",
"--secondary": "#f57c00",
"--secondary-variant": "#e65100",
"--background": "#212121",
"--background-variant": "#313131",
"--surface": "#424242",
"--surface-variant": "#616161",
"--popup-surface": "#757575",
"--focused-popup-surface": "#bdbdbd",
"--drag-marker": "rgb(255,0,0)",
"--spacer-color": "rgba(255, 255, 255, 0.25)",
"--one-hand-background": "#1b5e20",
"--one-hand-foreground": "#eeeeee",
"--incognito-icon-color": "#ffffff11",
"--on-primary": "#f0f0f0",
"--on-background": "#dcdcdc",
"--on-background-disabled": "#dcdcdc48",
"--on-surface": "#ffffff",
"--on-surface-variant": "#a0a0a0",
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"--shape-chip": "rounded-corner(50%, 50%, 50%, 50%)"
},
"keyboard": {
"background": "var(--background)"
"window": {
"background": "var(--background)",
"foreground": "var(--on-background)"
},
"key": {
@@ -25,170 +37,322 @@
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "1"
},
"key:pressed": {
"background": "var(--surface-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]": {
"key[code=10]": {
"background": "var(--primary)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]:pressed": {
"key[code=10]:pressed": {
"background": "var(--primary-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
"foreground": "var(--secondary)"
},
"key[code={c:space}]": {
"key[code=32]": {
"background": "var(--surface)",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp",
"text-overflow": "ellipsis"
},
"key[code=-201,-202,-203]": {
"font-size": "18sp"
},
"key[code=-204,-205]": {
"font-size": "12sp"
},
"key[code=-205]": {
"text-max-lines": "2"
},
"key[code=-11][shiftstate=`caps_lock`]": {
"foreground": "var(--secondary)"
},
"key-hint": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp"
"font-family": "monospace",
"font-size": "12sp",
"padding": "0dp 1dp 1dp 0dp",
"text-max-lines": "1"
},
"key-popup": {
"background": "#757575",
"key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"key-popup:focus": {
"background": "#bdbdbd",
"foreground": "var(--on-surface)"
"key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"key-popup-extended-indicator": {
"font-size": "16sp"
},
"smartbar": {
"font-size": "18sp"
},
"smartbar-shared-actions-toggle": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "6dp",
"shape": "circle()",
"shadow-elevation": "2dp"
},
"smartbar-extended-actions-toggle": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"margin": "6dp",
"shape": "circle()"
},
"smartbar-action-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-key:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-tile:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-tile:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"smartbar-actions-overflow": {
"margin": "4dp"
},
"smartbar-actions-overflow-customize-button": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"font-size": "14sp",
"shape": "circle()",
"shadow-elevation": "2dp"
"margin": "0dp 8dp 0dp 0dp",
"shape": "rounded-corner(24dp, 24dp, 24dp, 24dp)"
},
"smartbar-action-tile": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"font-size": "14sp",
"margin": "4dp",
"padding": "4dp",
"shape": "rounded-corner(20%, 20%, 20%, 20%)",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-action-tile:disabled": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile-icon": {
"font-size": "24sp",
"margin": "0dp 0dp 0dp 8dp"
},
"smartbar-actions-editor": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"smartbar-actions-editor-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "16sp"
"font-size": "16sp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"smartbar-actions-editor-subheader": {
"foreground": "var(--on-background)",
"font-size": "16sp"
"foreground": "var(--secondary)",
"font-size": "16sp",
"font-weight": "bold",
"padding": "12dp 16dp 12dp 8dp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile-grid": {
"margin": "4dp 0dp"
},
"smartbar-actions-editor-tile": {
"margin": "4dp",
"padding": "8dp",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile[code=-999]": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-actions-editor-tile[code=-991]": {
"foreground": "var(--drag-marker)"
},
"smartbar-candidate-word": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rectangle()"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rectangle()",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-word:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
"foreground": "var(--on-surface)"
},
"smartbar-candidate-word-secondary-text": {
"font-size": "8sp",
"margin": "0dp 2dp 0dp 0dp"
},
"smartbar-candidate-clip": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-clip:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
"foreground": "var(--on-surface)"
},
"smartbar-candidate-clip-icon": {
"margin": "0dp 0dp 4dp 0dp"
},
"smartbar-candidate-spacer": {
"foreground": "var(--surface)"
"foreground": "var(--spacer-color)"
},
"clipboard-header": {
"background": "transparent",
"foreground": "var(--on-surface)",
"foreground": "var(--on-background)",
"font-size": "16sp"
},
"clipboard-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"clipboard-header-button:disabled": {
"foreground": "var(--on-background-disabled)"
},
"clipboard-header-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"clipboard-subheader": {
"font-size": "14sp",
"margin": "6dp 10dp 6dp 6dp"
},
"clipboard-content": {
"padding": "10dp 0dp"
},
"clipboard-filter-row": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"padding": "0dp 0dp 4dp 0dp",
"shape": "var(--shape-variant)"
},
"clipboard-filter-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "4dp 4dp 0dp 4dp",
"padding": "8dp 4dp",
"shape": "var(--shape-chip)"
},
"clipboard-filter-chip[state=`active`]": {
"background": "var(--primary)",
"foreground": "var(--on-primary)"
},
"clipboard-filter-chip-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-grid": {
"shape": "var(--shape-variant)"
},
"clipboard-item": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "10",
"text-overflow": "ellipsis"
},
"clipboard-item[type=`text`]": {
"padding": "12dp 8dp"
},
"clipboard-item-description": {
"font-size": "12sp",
"font-style": "italic"
},
"clipboard-item-popup": {
"background": "var(--surface-variant)",
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
"clipboard-item-popup[type=`text`]": {
"padding": "12dp 8dp"
},
"emoji-key:pressed": {
"clipboard-item-timestamp": {
"font-size": "11sp",
"padding": "16dp 8dp"
},
"clipboard-item-actions": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"emoji-key-popup": {
"background": "#757575",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-tab": {
"foreground": "var(--on-background)"
"clipboard-item-action": {
"font-size": "16sp",
"padding": "12dp"
},
"emoji-tab:focus": {
"foreground": "var(--primary)"
"clipboard-item-action-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-clear-all-dialog": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)",
"shadow-elevation": "1dp"
},
"clipboard-clear-all-dialog-message": {
"padding": "16dp"
},
"clipboard-clear-all-dialog-buttons": {
"padding": "4dp"
},
"clipboard-clear-all-dialog-button": {
"background": "transparent",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)"
},
"clipboard-history-disabled-title": {
"font-weight": "bold"
},
"clipboard-history-disabled-message": {
"padding": "0dp 4dp 0dp 8dp"
},
"clipboard-history-disabled-button": {
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"shape": "rounded-corner(24dp,24dp,24dp,24dp)"
},
"clipboard-history-locked-title": {
"font-weight": "bold",
"text-align": "center"
},
"clipboard-history-locked-message": {
"padding": "0dp 4dp 0dp 0dp",
"text-align": "center"
},
"extracted-landscape-input-layout": {
@@ -213,15 +377,81 @@
},
"incognito-mode-indicator": {
"foreground": "#ffffff11"
"foreground": "var(--incognito-icon-color)"
},
"inline-autofill-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-subheader": {
"font-weight": "bold",
"margin": "4dp"
},
"media-emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
},
"media-emoji-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"media-emoji-key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"media-emoji-tab": {
"foreground": "var(--on-background)"
},
"media-emoji-tab:focus": {
"foreground": "var(--primary)"
},
"media-bottom-row-button": {
"padding": "16dp 0dp",
"shape": "var(--shape)"
},
"media-emoji-key-popup-extended-indicator": {
"foreground": "inherit"
},
"one-handed-panel": {
"background": "#1b5e20",
"foreground": "#eeeeee"
"background": "var(--one-hand-background)",
"foreground": "var(--one-hand-foreground)"
},
"system-nav-bar": {
"background": "var(--background)"
"subtype-panel": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"subtype-panel-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "18sp",
"padding": "12dp",
"text-align": "center",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"subtype-panel-list-item": {
"font-size": "16sp",
"padding": "16dp"
},
"subtype-panel-list-item-icon-leading": {
"font-size": "24sp",
"padding": "0dp 0dp 16dp 0dp"
},
"subtype-panel-list-item-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
}
}

View File

@@ -1,83 +1,119 @@
{
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
"@defines": {
"--primary": "#4caf50",
"--primary-variant": "#388e3c",
"--secondary": "#f57c00",
"--secondary-variant": "#e65100",
"--background": "#212121",
"--background-variant": "#313131",
"--surface": "#424242",
"--surface-variant": "#616161",
"--popup-surface": "#757575",
"--focused-popup-surface": "#bdbdbd",
"--drag-marker": "rgb(255,0,0)",
"--spacer-color": "rgba(255, 255, 255, 0.25)",
"--one-hand-background": "#1b5e20",
"--one-hand-foreground": "#eeeeee",
"--incognito-icon-color": "#ffffff11",
"--on-primary": "#f0f0f0",
"--on-background": "#dcdcdc",
"--on-background-disabled": "#dcdcdc48",
"--on-surface": "#ffffff",
"--on-surface-variant": "#a0a0a0",
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"--shape-chip": "rounded-corner(50%, 50%, 50%, 50%)"
},
"keyboard": {
"background": "var(--background)"
"window": {
"background": "var(--background)",
"foreground": "var(--on-background)"
},
"key": {
"background": "transparent",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)"
"shape": "var(--shape)",
"text-max-lines": "1"
},
"key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]": {
"key[code=10]": {
"background": "var(--primary)",
"foreground": "var(--on-surface)"
"foreground": "var(--on-surface)",
"margin": "0dp 6dp"
},
"key[code={c:enter}]:pressed": {
"key[code=10]:pressed": {
"background": "var(--primary-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
"foreground": "var(--secondary)"
},
"key[code={c:space}]": {
"key[code=32]": {
"background": "var(--surface)",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp",
"margin": "0dp 6dp",
"text-overflow": "ellipsis"
},
"key[code=-201,-202,-203]": {
"font-size": "18sp"
},
"key[code=-204,-205]": {
"font-size": "12sp"
},
"key[code=-205]": {
"text-max-lines": "2"
},
"key[code=-11][shiftstate=`caps_lock`]": {
"foreground": "var(--secondary)"
},
"key-hint": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp"
"font-size": "12sp",
"font-family": "monospace",
"padding": "0dp 1dp 1dp 0dp",
"text-max-lines": "1"
},
"key-popup": {
"background": "#757575",
"key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"key-popup:focus": {
"background": "#bdbdbd",
"foreground": "var(--on-surface)"
"key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape)"
},
"key-popup-extended-indicator": {
"font-size": "16sp"
},
"smartbar": {
"font-size": "18sp"
},
"smartbar-shared-actions-toggle": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "6dp",
"shape": "circle()",
"shadow-elevation": "2dp"
},
"smartbar-extended-actions-toggle": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"margin": "6dp",
"shape": "circle()"
},
"smartbar-action-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-key:pressed": {
@@ -85,109 +121,244 @@
"foreground": "var(--on-surface)"
},
"smartbar-action-key:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-tile:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-tile:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"smartbar-actions-overflow": {
"margin": "4dp"
},
"smartbar-actions-overflow-customize-button": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"font-size": "14sp",
"shape": "circle()",
"shadow-elevation": "2dp"
"margin": "0dp 8dp 0dp 0dp",
"shape": "rounded-corner(24dp, 24dp, 24dp, 24dp)"
},
"smartbar-action-tile": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"font-size": "14sp",
"margin": "4dp",
"padding": "4dp",
"shape": "rounded-corner(20%, 20%, 20%, 20%)",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-action-tile:disabled": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile-icon": {
"font-size": "24sp",
"margin": "0dp 0dp 0dp 8dp"
},
"smartbar-actions-editor": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"smartbar-actions-editor-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "16sp"
"font-size": "16sp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"smartbar-actions-editor-subheader": {
"foreground": "var(--on-background)",
"font-size": "16sp"
"font-size": "16sp",
"font-weight": "bold",
"padding": "12dp 16dp 12dp 8dp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile-grid": {
"margin": "4dp 0dp"
},
"smartbar-actions-editor-tile": {
"margin": "4dp",
"padding": "8dp",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile[code=-999]": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-actions-editor-tile[code=-991]": {
"foreground": "var(--drag-marker)"
},
"smartbar-candidate-word": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rectangle()"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rectangle()",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-word:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
},
"smartbar-candidate-word-secondary-text": {
"font-size": "8sp",
"margin": "0dp 2dp 0dp 0dp"
},
"smartbar-candidate-clip": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-clip:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
},
"smartbar-candidate-clip-icon": {
"margin": "0dp 0dp 4dp 0dp"
},
"smartbar-candidate-spacer": {
"foreground": "var(--surface)"
},
"clipboard-header": {
"background": "transparent",
"foreground": "var(--on-surface)",
"foreground": "var(--on-background)",
"font-size": "16sp"
},
"clipboard-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"clipboard-header-button:disabled": {
"foreground": "var(--on-background-disabled)"
},
"clipboard-header-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"clipboard-subheader": {
"font-size": "14sp",
"margin": "6dp 10dp 6dp 6dp"
},
"clipboard-content": {
"padding": "10dp 0dp"
},
"clipboard-filter-row": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"padding": "0dp 0dp 4dp 0dp",
"shape": "var(--shape-variant)"
},
"clipboard-filter-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "4dp 4dp 0dp 4dp",
"padding": "8dp 4dp",
"shape": "var(--shape-chip)"
},
"clipboard-filter-chip[state=`active`]": {
"background": "var(--primary)",
"foreground": "var(--on-primary)"
},
"clipboard-filter-chip-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-grid": {
"shape": "var(--shape-variant)"
},
"clipboard-item": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "10",
"text-overflow": "ellipsis"
},
"clipboard-item[type=`text`]": {
"padding": "12dp 8dp"
},
"clipboard-item-description": {
"font-size": "12sp",
"font-style": "italic"
},
"clipboard-item-popup": {
"background": "var(--surface-variant)",
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
"clipboard-item-popup[type=`text`]": {
"padding": "12dp 8dp"
},
"emoji-key:pressed": {
"clipboard-item-timestamp": {
"font-size": "11sp",
"padding": "16dp 8dp"
},
"clipboard-item-actions": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"emoji-key-popup": {
"background": "#757575",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-tab": {
"foreground": "var(--on-background)"
"clipboard-item-action": {
"font-size": "16sp",
"padding": "12dp"
},
"emoji-tab:focus": {
"foreground": "var(--primary)"
"clipboard-item-action-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-clear-all-dialog": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)",
"shadow-elevation": "1dp"
},
"clipboard-clear-all-dialog-message": {
"padding": "16dp"
},
"clipboard-clear-all-dialog-buttons": {
"padding": "4dp"
},
"clipboard-clear-all-dialog-button": {
"background": "transparent",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)"
},
"clipboard-history-disabled-title": {
"font-weight": "bold"
},
"clipboard-history-disabled-message": {
"padding": "0dp 4dp 0dp 8dp"
},
"clipboard-history-disabled-button": {
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"shape": "rounded-corner(24dp,24dp,24dp,24dp)"
},
"clipboard-history-locked-title": {
"font-weight": "bold",
"text-align": "center"
},
"clipboard-history-locked-message": {
"padding": "0dp 4dp 0dp 0dp",
"text-align": "center"
},
"extracted-landscape-input-layout": {
@@ -212,15 +383,81 @@
},
"incognito-mode-indicator": {
"foreground": "#ffffff11"
"foreground": "var(--incognito-icon-color)"
},
"inline-autofill-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-subheader": {
"font-weight": "bold",
"margin": "4dp"
},
"media-emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
},
"media-emoji-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"media-emoji-key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"media-emoji-tab": {
"foreground": "var(--on-background)"
},
"media-emoji-tab:focus": {
"foreground": "var(--primary)"
},
"media-bottom-row-button": {
"padding": "16dp 0dp",
"shape": "var(--shape)"
},
"media-emoji-key-popup-extended-indicator": {
"foreground": "inherit"
},
"one-handed-panel": {
"background": "#1b5e20",
"foreground": "#eeeeee"
"background": "var(--one-hand-background)",
"foreground": "var(--one-hand-foreground)"
},
"system-nav-bar": {
"background": "var(--background)"
"subtype-panel": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"subtype-panel-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "18sp",
"padding": "12dp",
"text-align": "center",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"subtype-panel-list-item": {
"font-size": "16sp",
"padding": "16dp"
},
"subtype-panel-list-item-icon-leading": {
"font-size": "24sp",
"padding": "0dp 0dp 16dp 0dp"
},
"subtype-panel-list-item-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
}
}

View File

@@ -1,23 +1,35 @@
{
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
"@defines": {
"--primary": "#388e3c",
"--primary-variant": "#306d32",
"--secondary": "#ff9800",
"--secondary-variant": "#804c00",
"--background": "#000000",
"--background-variant": "#111111",
"--surface": "#212121",
"--surface-variant": "#3d3d3d",
"--popup-surface": "#424242",
"--focused-popup-surface": "#707070",
"--drag-marker": "rgb(255,0,0)",
"--spacer-color": "rgba(255, 255, 255, 0.25)",
"--one-hand-background": "#1b5e20",
"--one-hand-foreground": "#eeeeee",
"--incognito-icon-color": "#ffffff11",
"--on-primary": "#f0f0f0",
"--on-background-disabled": "#dcdcdc48",
"--on-background": "#eeeeee",
"--on-surface": "#eeeeee",
"--on-surface-variant": "#ffffff73",
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"--shape-chip": "rounded-corner(50%, 50%, 50%, 50%)"
},
"keyboard": {
"background": "var(--background)"
"window": {
"background": "var(--background)",
"foreground": "var(--on-background)"
},
"key": {
@@ -25,60 +37,81 @@
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "1"
},
"key:pressed": {
"background": "var(--surface-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]": {
"key[code=10]": {
"background": "var(--primary)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]:pressed": {
"key[code=10]:pressed": {
"background": "var(--primary-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
"foreground": "var(--secondary)"
},
"key[code={c:space}]": {
"key[code=32]": {
"background": "var(--surface)",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp",
"text-overflow": "ellipsis"
},
"key[code=-201,-202,-203]": {
"font-size": "18sp"
},
"key[code=-204,-205]": {
"font-size": "12sp"
},
"key[code=-205]": {
"text-max-lines": "2"
},
"key[code=-11][shiftstate=`caps_lock`]": {
"foreground": "var(--secondary)"
},
"key-hint": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp"
"font-family": "monospace",
"font-size": "12sp",
"padding": "0dp 1dp 1dp 0dp",
"text-max-lines": "1"
},
"key-popup": {
"background": "#424242",
"key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"key-popup:focus": {
"background": "#707070",
"foreground": "var(--on-surface)"
"key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"key-popup-extended-indicator": {
"font-size": "16sp"
},
"smartbar": {
"font-size": "18sp"
},
"smartbar-shared-actions-toggle": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "6dp",
"shape": "circle()",
"shadow-elevation": "2dp"
},
"smartbar-extended-actions-toggle": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"margin": "6dp",
"shape": "circle()"
},
"smartbar-action-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-key:pressed": {
@@ -86,109 +119,244 @@
"foreground": "var(--on-surface)"
},
"smartbar-action-key:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-tile:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-tile:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"smartbar-actions-overflow": {
"margin": "4dp"
},
"smartbar-actions-overflow-customize-button": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"font-size": "14sp",
"shape": "circle()",
"shadow-elevation": "2dp"
"margin": "0dp 8dp 0dp 0dp",
"shape": "rounded-corner(24dp, 24dp, 24dp, 24dp)"
},
"smartbar-action-tile": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"font-size": "14sp",
"margin": "4dp",
"padding": "4dp",
"shape": "rounded-corner(20%, 20%, 20%, 20%)",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-action-tile:disabled": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile-icon": {
"font-size": "24sp",
"margin": "0dp 0dp 0dp 8dp"
},
"smartbar-actions-editor": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"smartbar-actions-editor-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "16sp"
"font-size": "16sp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"smartbar-actions-editor-subheader": {
"foreground": "var(--on-background)",
"font-size": "16sp"
"foreground": "var(--secondary)",
"font-size": "16sp",
"font-weight": "bold",
"padding": "12dp 16dp 12dp 8dp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile-grid": {
"margin": "4dp 0dp"
},
"smartbar-actions-editor-tile": {
"margin": "4dp",
"padding": "8dp",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile[code=-999]": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-actions-editor-tile[code=-991]": {
"foreground": "var(--drag-marker)"
},
"smartbar-candidate-word": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rectangle()"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rectangle()",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-word:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
"foreground": "var(--on-surface)"
},
"smartbar-candidate-word-secondary-text": {
"font-size": "8sp",
"margin": "0dp 2dp 0dp 0dp"
},
"smartbar-candidate-clip": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-clip:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
"foreground": "var(--on-surface)"
},
"smartbar-candidate-clip-icon": {
"margin": "0dp 0dp 4dp 0dp"
},
"smartbar-candidate-spacer": {
"foreground": "var(--surface)"
"foreground": "var(--spacer-color)"
},
"clipboard-header": {
"background": "transparent",
"foreground": "var(--on-surface)",
"foreground": "var(--on-background)",
"font-size": "16sp"
},
"clipboard-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"clipboard-header-button:disabled": {
"foreground": "var(--on-background-disabled)"
},
"clipboard-header-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"clipboard-subheader": {
"font-size": "14sp",
"margin": "6dp 10dp 6dp 6dp"
},
"clipboard-content": {
"padding": "10dp 0dp"
},
"clipboard-filter-row": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"padding": "0dp 0dp 4dp 0dp",
"shape": "var(--shape-variant)"
},
"clipboard-filter-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "4dp 4dp 0dp 4dp",
"padding": "8dp 4dp",
"shape": "var(--shape-chip)"
},
"clipboard-filter-chip[state=`active`]": {
"background": "var(--primary)",
"foreground": "var(--on-primary)"
},
"clipboard-filter-chip-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-grid": {
"shape": "var(--shape-variant)"
},
"clipboard-item": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "10",
"text-overflow": "ellipsis"
},
"clipboard-item[type=`text`]": {
"padding": "12dp 8dp"
},
"clipboard-item-description": {
"font-size": "12sp",
"font-style": "italic"
},
"clipboard-item-popup": {
"background": "var(--surface-variant)",
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
"clipboard-item-popup[type=`text`]": {
"padding": "12dp 8dp"
},
"emoji-key:pressed": {
"clipboard-item-timestamp": {
"font-size": "11sp",
"padding": "16dp 8dp"
},
"clipboard-item-actions": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"emoji-key-popup": {
"background": "#757575",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-tab": {
"foreground": "var(--on-background)"
"clipboard-item-action": {
"font-size": "16sp",
"padding": "12dp"
},
"emoji-tab:focus": {
"foreground": "var(--primary)"
"clipboard-item-action-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-clear-all-dialog": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)",
"shadow-elevation": "1dp"
},
"clipboard-clear-all-dialog-message": {
"padding": "16dp"
},
"clipboard-clear-all-dialog-buttons": {
"padding": "4dp"
},
"clipboard-clear-all-dialog-button": {
"background": "transparent",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)"
},
"clipboard-history-disabled-title": {
"font-weight": "bold"
},
"clipboard-history-disabled-message": {
"padding": "0dp 4dp 0dp 8dp"
},
"clipboard-history-disabled-button": {
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"shape": "rounded-corner(24dp,24dp,24dp,24dp)"
},
"clipboard-history-locked-title": {
"font-weight": "bold",
"text-align": "center"
},
"clipboard-history-locked-message": {
"padding": "0dp 4dp 0dp 0dp",
"text-align": "center"
},
"extracted-landscape-input-layout": {
@@ -199,29 +367,95 @@
"foreground": "var(--on-background)",
"font-size": "16sp",
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"border-color": "var(--secondary-variant)",
"border-width": "1dp"
"border-color": "var(--secondary)",
"border-width": "2dp"
},
"extracted-landscape-input-action": {
"background": "var(--surface)",
"background": "var(--primary)",
"foreground": "var(--on-surface)",
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
},
"glide-trail": {
"foreground": "var(--primary-variant)"
"foreground": "var(--primary)"
},
"incognito-mode-indicator": {
"foreground": "#ffffff11"
"foreground": "var(--incognito-icon-color)"
},
"inline-autofill-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-subheader": {
"font-weight": "bold",
"margin": "4dp"
},
"media-emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
},
"media-emoji-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"media-emoji-key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"media-emoji-tab": {
"foreground": "var(--on-background)"
},
"media-emoji-tab:focus": {
"foreground": "var(--primary)"
},
"media-bottom-row-button": {
"padding": "16dp 0dp",
"shape": "var(--shape)"
},
"media-emoji-key-popup-extended-indicator": {
"foreground": "inherit"
},
"one-handed-panel": {
"background": "#000000",
"foreground": "#eeeeee"
"background": "var(--one-hand-background)",
"foreground": "var(--one-hand-foreground)"
},
"system-nav-bar": {
"background": "var(--background)"
"subtype-panel": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"subtype-panel-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "18sp",
"padding": "12dp",
"text-align": "center",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"subtype-panel-list-item": {
"font-size": "16sp",
"padding": "16dp"
},
"subtype-panel-list-item-icon-leading": {
"font-size": "24sp",
"padding": "0dp 0dp 16dp 0dp"
},
"subtype-panel-list-item-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
}
}

View File

@@ -1,83 +1,119 @@
{
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
"@defines": {
"--primary": "#388e3c",
"--primary-variant": "#306d32",
"--secondary": "#ff9800",
"--secondary-variant": "#804c00",
"--background": "#000000",
"--background-variant": "#111111",
"--surface": "#212121",
"--surface-variant": "#3d3d3d",
"--popup-surface": "#424242",
"--focused-popup-surface": "#707070",
"--drag-marker": "rgb(255,0,0)",
"--spacer-color": "rgba(255, 255, 255, 0.25)",
"--one-hand-background": "#1b5e20",
"--one-hand-foreground": "#eeeeee",
"--incognito-icon-color": "#ffffff11",
"--on-primary": "#f0f0f0",
"--on-background-disabled": "#dcdcdc48",
"--on-background": "#eeeeee",
"--on-surface": "#eeeeee",
"--on-surface-variant": "#ffffff73",
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"--shape-chip": "rounded-corner(50%, 50%, 50%, 50%)"
},
"keyboard": {
"background": "var(--background)"
"window": {
"background": "var(--background)",
"foreground": "var(--on-background)"
},
"key": {
"background": "transparent",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)"
"shape": "var(--shape)",
"text-max-lines": "1"
},
"key:pressed": {
"background": "#6161617f",
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"key[code={c:enter}]": {
"key[code=10]": {
"background": "var(--primary)",
"foreground": "var(--on-surface)"
"foreground": "var(--on-surface)",
"margin": "0dp 6dp"
},
"key[code={c:enter}]:pressed": {
"key[code=10]:pressed": {
"background": "var(--primary-variant)",
"foreground": "var(--on-surface)"
},
"key[code={c:shift}][shiftstate={sh:caps_lock}]": {
"foreground": "var(--secondary)"
},
"key[code={c:space}]": {
"background": "#61616146",
"key[code=32]": {
"background": "var(--surface)",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp",
"margin": "0dp 6dp",
"text-overflow": "ellipsis"
},
"key[code=-201,-202,-203]": {
"font-size": "18sp"
},
"key[code=-204,-205]": {
"font-size": "12sp"
},
"key[code=-205]": {
"text-max-lines": "2"
},
"key[code=-11][shiftstate=`caps_lock`]": {
"foreground": "var(--secondary)"
},
"key-hint": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"font-size": "12sp"
"font-size": "12sp",
"font-family": "monospace",
"padding": "0dp 1dp 1dp 0dp",
"text-max-lines": "1"
},
"key-popup": {
"background": "#363636",
"key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"key-popup:focus": {
"background": "#5F5F5F",
"foreground": "var(--on-surface)"
"key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape)"
},
"key-popup-extended-indicator": {
"font-size": "16sp"
},
"smartbar": {
"font-size": "18sp"
},
"smartbar-shared-actions-toggle": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "6dp",
"shape": "circle()",
"shadow-elevation": "2dp"
},
"smartbar-extended-actions-toggle": {
"background": "transparent",
"foreground": "var(--on-surface-variant)",
"margin": "6dp",
"shape": "circle()"
},
"smartbar-action-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-key:pressed": {
@@ -85,109 +121,244 @@
"foreground": "var(--on-surface)"
},
"smartbar-action-key:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "18sp",
"shape": "var(--shape)"
},
"smartbar-action-tile:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"smartbar-action-tile:disabled": {
"background": "transparent",
"foreground": "#dcdcdc48"
"smartbar-actions-overflow": {
"margin": "4dp"
},
"smartbar-actions-overflow-customize-button": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"font-size": "14sp",
"shape": "circle()",
"shadow-elevation": "2dp"
"margin": "0dp 8dp 0dp 0dp",
"shape": "rounded-corner(24dp, 24dp, 24dp, 24dp)"
},
"smartbar-action-tile": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"font-size": "14sp",
"margin": "4dp",
"padding": "4dp",
"shape": "rounded-corner(20%, 20%, 20%, 20%)",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-action-tile:disabled": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-action-tile-icon": {
"font-size": "24sp",
"margin": "0dp 0dp 0dp 8dp"
},
"smartbar-actions-editor": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"smartbar-actions-editor-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "16sp"
"font-size": "16sp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"smartbar-actions-editor-subheader": {
"foreground": "var(--on-background)",
"font-size": "16sp"
"font-size": "16sp",
"font-weight": "bold",
"padding": "12dp 16dp 12dp 8dp",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile-grid": {
"margin": "4dp 0dp"
},
"smartbar-actions-editor-tile": {
"margin": "4dp",
"padding": "8dp",
"text-align": "center",
"text-max-lines": "2",
"text-overflow": "ellipsis"
},
"smartbar-actions-editor-tile[code=-999]": {
"foreground": "var(--on-background-disabled)"
},
"smartbar-actions-editor-tile[code=-991]": {
"foreground": "var(--drag-marker)"
},
"smartbar-candidate-word": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rectangle()"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rectangle()",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-word:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
},
"smartbar-candidate-word-secondary-text": {
"font-size": "8sp",
"margin": "0dp 2dp 0dp 0dp"
},
"smartbar-candidate-clip": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "14sp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
"margin": "4dp",
"padding": "8dp 0dp",
"shape": "rounded-corner(8%, 8%, 8%, 8%)",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"smartbar-candidate-clip:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-background)"
},
"smartbar-candidate-clip-icon": {
"margin": "0dp 0dp 4dp 0dp"
},
"smartbar-candidate-spacer": {
"foreground": "var(--surface)"
},
"clipboard-header": {
"background": "transparent",
"foreground": "var(--on-surface)",
"foreground": "var(--on-background)",
"font-size": "16sp"
},
"clipboard-header-button": {
"margin": "4dp",
"shape": "circle()"
},
"clipboard-header-button:disabled": {
"foreground": "var(--on-background-disabled)"
},
"clipboard-header-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"clipboard-subheader": {
"font-size": "14sp",
"margin": "6dp 10dp 6dp 6dp"
},
"clipboard-content": {
"padding": "10dp 0dp"
},
"clipboard-filter-row": {
"background": "var(--background-variant)",
"foreground": "var(--on-background)",
"padding": "0dp 0dp 4dp 0dp",
"shape": "var(--shape-variant)"
},
"clipboard-filter-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"margin": "4dp 4dp 0dp 4dp",
"padding": "8dp 4dp",
"shape": "var(--shape-chip)"
},
"clipboard-filter-chip[state=`active`]": {
"background": "var(--primary)",
"foreground": "var(--on-primary)"
},
"clipboard-filter-chip-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-grid": {
"shape": "var(--shape-variant)"
},
"clipboard-item": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
"shadow-elevation": "2dp",
"text-max-lines": "10",
"text-overflow": "ellipsis"
},
"clipboard-item[type=`text`]": {
"padding": "12dp 8dp"
},
"clipboard-item-description": {
"font-size": "12sp",
"font-style": "italic"
},
"clipboard-item-popup": {
"background": "var(--surface-variant)",
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "14sp",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
"clipboard-item-popup[type=`text`]": {
"padding": "12dp 8dp"
},
"emoji-key:pressed": {
"clipboard-item-timestamp": {
"font-size": "11sp",
"padding": "16dp 8dp"
},
"clipboard-item-actions": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"emoji-key-popup": {
"background": "#757575",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"margin": "4dp",
"shape": "var(--shape-variant)",
"shadow-elevation": "2dp"
},
"emoji-tab": {
"foreground": "var(--on-background)"
"clipboard-item-action": {
"font-size": "16sp",
"padding": "12dp"
},
"emoji-tab:focus": {
"foreground": "var(--primary)"
"clipboard-item-action-text": {
"margin": "4dp 0dp 0dp 0dp"
},
"clipboard-clear-all-dialog": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)",
"shadow-elevation": "1dp"
},
"clipboard-clear-all-dialog-message": {
"padding": "16dp"
},
"clipboard-clear-all-dialog-buttons": {
"padding": "4dp"
},
"clipboard-clear-all-dialog-button": {
"background": "transparent",
"foreground": "var(--on-surface)",
"shape": "var(--shape-variant)"
},
"clipboard-history-disabled-title": {
"font-weight": "bold"
},
"clipboard-history-disabled-message": {
"padding": "0dp 4dp 0dp 8dp"
},
"clipboard-history-disabled-button": {
"background": "var(--primary)",
"foreground": "var(--on-primary)",
"shape": "rounded-corner(24dp,24dp,24dp,24dp)"
},
"clipboard-history-locked-title": {
"font-weight": "bold",
"text-align": "center"
},
"clipboard-history-locked-message": {
"padding": "0dp 4dp 0dp 0dp",
"text-align": "center"
},
"extracted-landscape-input-layout": {
@@ -198,29 +369,95 @@
"foreground": "var(--on-background)",
"font-size": "16sp",
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
"border-color": "var(--secondary-variant)",
"border-width": "1dp"
"border-color": "var(--secondary)",
"border-width": "2dp"
},
"extracted-landscape-input-action": {
"background": "var(--surface)",
"background": "var(--primary)",
"foreground": "var(--on-surface)",
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
},
"glide-trail": {
"foreground": "var(--primary-variant)"
"foreground": "var(--primary)"
},
"incognito-mode-indicator": {
"foreground": "#ffffff11"
"foreground": "var(--incognito-icon-color)"
},
"inline-autofill-chip": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-subheader": {
"font-weight": "bold",
"margin": "4dp"
},
"media-emoji-key": {
"background": "transparent",
"foreground": "var(--on-background)",
"font-size": "22sp",
"shape": "var(--shape)"
},
"media-emoji-key:pressed": {
"background": "var(--surface)",
"foreground": "var(--on-surface)"
},
"media-emoji-key-popup-box": {
"background": "var(--popup-surface)",
"foreground": "var(--on-surface)",
"font-size": "22sp",
"shape": "var(--shape)",
"shadow-elevation": "2dp"
},
"media-emoji-key-popup-element:focus": {
"background": "var(--focused-popup-surface)",
"shape": "var(--shape)"
},
"media-emoji-tab": {
"foreground": "var(--on-background)"
},
"media-emoji-tab:focus": {
"foreground": "var(--primary)"
},
"media-bottom-row-button": {
"padding": "16dp 0dp",
"shape": "var(--shape)"
},
"media-emoji-key-popup-extended-indicator": {
"foreground": "inherit"
},
"one-handed-panel": {
"background": "#000000",
"foreground": "#eeeeee"
"background": "var(--one-hand-background)",
"foreground": "var(--one-hand-foreground)"
},
"system-nav-bar": {
"background": "var(--background)"
"subtype-panel": {
"background": "var(--background)",
"foreground": "var(--on-background)",
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
},
"subtype-panel-header": {
"background": "var(--surface)",
"foreground": "var(--on-surface)",
"font-size": "18sp",
"padding": "12dp",
"text-align": "center",
"text-max-lines": "1",
"text-overflow": "ellipsis"
},
"subtype-panel-list-item": {
"font-size": "16sp",
"padding": "16dp"
},
"subtype-panel-list-item-icon-leading": {
"font-size": "24sp",
"padding": "0dp 0dp 16dp 0dp"
},
"subtype-panel-list-item-text": {
"text-max-lines": "1",
"text-overflow": "ellipsis"
}
}

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ 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
@@ -61,7 +60,6 @@ class FlorisApplication : Application() {
System.loadLibrary("fl_native")
} catch (_: Exception) {
}
FlorisImeTheme.init()
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package dev.patrickgold.florisboard
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration
import android.inputmethodservice.ExtractEditText
import android.os.Build
@@ -46,11 +47,11 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material3.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -78,6 +79,8 @@ import dev.patrickgold.florisboard.app.devtools.DevtoolsOverlay
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.ime.ImeUiMode
import dev.patrickgold.florisboard.ime.clipboard.ClipboardInputLayout
import dev.patrickgold.florisboard.ime.core.SelectSubtypePanel
import dev.patrickgold.florisboard.ime.core.isSubtypeSelectionShowing
import dev.patrickgold.florisboard.ime.editor.EditorRange
import dev.patrickgold.florisboard.ime.editor.FlorisEditorInfo
import dev.patrickgold.florisboard.ime.input.InputFeedbackController
@@ -98,7 +101,7 @@ 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.compose.FlorisButton
import dev.patrickgold.florisboard.ime.theme.WallpaperChangeReceiver
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
import dev.patrickgold.florisboard.lib.compose.SystemUiIme
import dev.patrickgold.florisboard.lib.devtools.LogTopic
@@ -106,17 +109,11 @@ import dev.patrickgold.florisboard.lib.devtools.flogError
import dev.patrickgold.florisboard.lib.devtools.flogInfo
import dev.patrickgold.florisboard.lib.devtools.flogWarning
import dev.patrickgold.florisboard.lib.observeAsTransformingState
import org.florisboard.lib.snygg.ui.SnyggSurface
import org.florisboard.lib.snygg.ui.shape
import org.florisboard.lib.snygg.ui.snyggBackground
import org.florisboard.lib.snygg.ui.snyggBorder
import org.florisboard.lib.snygg.ui.snyggShadow
import org.florisboard.lib.snygg.ui.solidColor
import org.florisboard.lib.snygg.ui.spSize
import dev.patrickgold.florisboard.lib.util.ViewUtils
import dev.patrickgold.florisboard.lib.util.debugSummarize
import dev.patrickgold.florisboard.lib.util.launchActivity
import dev.patrickgold.jetpref.datastore.model.observeAsState
import java.lang.ref.WeakReference
import org.florisboard.lib.android.AndroidInternalR
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.isOrientationLandscape
@@ -124,7 +121,11 @@ 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
import org.florisboard.lib.snygg.ui.SnyggBox
import org.florisboard.lib.snygg.ui.SnyggButton
import org.florisboard.lib.snygg.ui.SnyggRow
import org.florisboard.lib.snygg.ui.SnyggText
import org.florisboard.lib.snygg.ui.rememberSnyggThemeQuery
/**
* Global weak reference for the [FlorisImeService] class. This is needed as certain actions (request hide, switch to
@@ -231,10 +232,10 @@ class FlorisImeService : LifecycleInputMethodService() {
val imm = ims.systemServiceOrNull(InputMethodManager::class) ?: return false
val list: List<InputMethodInfo> = imm.enabledInputMethodList
for (el in list) {
for (i in 0 until el.subtypeCount){
for (i in 0 until el.subtypeCount) {
if (el.getSubtypeAt(i).mode != "voice") continue
if (AndroidVersion.ATLEAST_API28_P) {
ims.switchInputMethod(el.id)
ims.switchInputMethod(el.id, el.getSubtypeAt(i))
return true
} else {
ims.window.window?.let { window ->
@@ -266,6 +267,8 @@ class FlorisImeService : LifecycleInputMethodService() {
private var isExtractUiShown by mutableStateOf(false)
private var resourcesContext by mutableStateOf(this as Context)
private val wallpaperChangeReceiver = WallpaperChangeReceiver()
init {
setTheme(R.style.FlorisImeTheme)
}
@@ -276,9 +279,23 @@ class FlorisImeService : LifecycleInputMethodService() {
WindowCompat.setDecorFitsSystemWindows(window.window!!, false)
subtypeManager.activeSubtypeFlow.collectLatestIn(lifecycleScope) { subtype ->
val config = Configuration(resources.configuration)
config.setLocale(subtype.primaryLocale.base)
if (prefs.localization.displayKeyboardLabelsInSubtypeLanguage.get()) {
config.setLocale(subtype.primaryLocale.base)
}
resourcesContext = createConfigurationContext(config)
}
prefs.localization.displayKeyboardLabelsInSubtypeLanguage.observeForever { shouldSync ->
val config = Configuration(resources.configuration)
if (shouldSync) {
config.setLocale(subtypeManager.activeSubtype.primaryLocale.base)
}
resourcesContext = createConfigurationContext(config)
}
prefs.physicalKeyboard.showOnScreenKeyboard.observeForever {
updateInputViewShown()
}
@Suppress("DEPRECATION") // We do not retrieve the wallpaper but only listen to changes
registerReceiver(wallpaperChangeReceiver, IntentFilter(Intent.ACTION_WALLPAPER_CHANGED))
}
override fun onCreateInputView(): View {
@@ -317,6 +334,7 @@ class FlorisImeService : LifecycleInputMethodService() {
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(wallpaperChangeReceiver)
FlorisImeServiceReference = WeakReference(null)
inputWindowView = null
}
@@ -341,6 +359,13 @@ class FlorisImeService : LifecycleInputMethodService() {
}
}
override fun onEvaluateInputViewShown(): Boolean {
val config = resources.configuration
return super.onEvaluateInputViewShown()
|| config.keyboard == Configuration.KEYBOARD_NOKEYS
|| prefs.physicalKeyboard.showOnScreenKeyboard.get()
}
override fun onUpdateSelection(
oldSelStart: Int,
oldSelEnd: Int,
@@ -447,6 +472,10 @@ class FlorisImeService : LifecycleInputMethodService() {
flogInfo(LogTopic.IMS_EVENTS) { "Creating inline suggestions request" }
val stylesBundle = themeManager.createInlineSuggestionUiStyleBundle(this)
if (stylesBundle == null) {
flogWarning(LogTopic.IMS_EVENTS) { "Failed to retrieve inline suggestions style bundle" }
return null
}
val spec = InlinePresentationSpec.Builder(
InlineSuggestionUiSmallestSize,
InlineSuggestionUiBiggestSize,
@@ -494,7 +523,9 @@ class FlorisImeService : LifecycleInputMethodService() {
outInsets.visibleTopInsets = visibleTopY
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_REGION
val left = 0
val top = if (keyboardManager.activeState.isBottomSheetShowing()) { 0 } else {
val top = if (keyboardManager.activeState.isBottomSheetShowing() || keyboardManager.activeState.isSubtypeSelectionShowing()) {
0
} else {
visibleTopY - if (needAdditionalOverlay) FlorisImeSizing.Static.smartbarHeightPx else 0
}
val right = inputViewSize.width
@@ -507,7 +538,8 @@ class FlorisImeService : LifecycleInputMethodService() {
*/
private fun updateSoftInputWindowLayoutParameters() {
val w = window?.window ?: return
WindowCompat.setDecorFitsSystemWindows(w, true)
// TODO: Verify that this doesn't give us a padding problem
WindowCompat.setDecorFitsSystemWindows(w, false)
ViewUtils.updateLayoutHeightOf(w, WindowManager.LayoutParams.MATCH_PARENT)
val layoutHeight = if (isFullscreenUiMode) {
WindowManager.LayoutParams.WRAP_CONTENT
@@ -544,19 +576,18 @@ class FlorisImeService : LifecycleInputMethodService() {
ProvideKeyboardRowBaseHeight {
CompositionLocalProvider(LocalInputFeedbackController provides inputFeedbackController) {
FlorisImeTheme {
// Do not apply system bar padding here yet, we want to draw it ourselves
Column(modifier = Modifier.fillMaxWidth()) {
if (!(isFullscreenUiMode && isExtractUiShown)) {
Box(
DevtoolsOverlay(
modifier = Modifier
.fillMaxWidth()
.weight(1f),
) {
DevtoolsUi()
}
)
}
ImeUi()
SystemUiIme()
}
SystemUiIme()
}
}
}
@@ -567,25 +598,27 @@ class FlorisImeService : LifecycleInputMethodService() {
@Composable
private fun ImeUi() {
val state by keyboardManager.activeState.collectAsState()
val keyboardStyle = FlorisImeTheme.style.get(
element = FlorisImeUi.Keyboard,
mode = state.inputShiftState.value,
val attributes = mapOf(
FlorisImeUi.Attr.Mode to state.keyboardMode.toString(),
FlorisImeUi.Attr.ShiftState to state.inputShiftState.toString(),
)
val layoutDirection = LocalLayoutDirection.current
SideEffect {
if (keyboardManager.activeState.layoutDirection != layoutDirection) {
keyboardManager.activeState.layoutDirection = layoutDirection
}
LaunchedEffect(layoutDirection) {
keyboardManager.activeState.layoutDirection = layoutDirection
}
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
SnyggSurface(
SnyggBox(
elementName = FlorisImeUi.Window.elementName,
attributes = attributes,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.onGloballyPositioned { coords -> inputViewSize = coords.size }
.onGloballyPositioned { coords -> inputViewSize = coords.size },
clickAndSemanticsModifier = Modifier
// Do not remove below line or touch input may get stuck
.pointerInteropFilter { false },
style = keyboardStyle,
supportsBackgroundImage = true,
allowClip = false,
) {
val configuration = LocalConfiguration.current
val bottomOffset by if (configuration.isOrientationPortrait()) {
@@ -597,17 +630,18 @@ class FlorisImeService : LifecycleInputMethodService() {
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
// FIXME: removing this fixes the Smartbar sizing but breaks one-handed-mode
//.height(IntrinsicSize.Min)
// Apply system bars padding here (we already drew our keyboard background)
.safeDrawingPadding()
.padding(bottom = bottomOffset),
) {
val oneHandedMode by prefs.keyboard.oneHandedMode.observeAsState()
val oneHandedModeEnabled by prefs.keyboard.oneHandedModeEnabled.observeAsState()
val oneHandedModeScaleFactor by prefs.keyboard.oneHandedModeScaleFactor.observeAsState()
val keyboardWeight = when {
oneHandedMode == OneHandedMode.OFF || configuration.isOrientationLandscape() -> 1f
!oneHandedModeEnabled || configuration.isOrientationLandscape() -> 1f
else -> oneHandedModeScaleFactor / 100f
}
if (oneHandedMode == OneHandedMode.END && configuration.isOrientationPortrait()) {
if (oneHandedModeEnabled && oneHandedMode == OneHandedMode.END && configuration.isOrientationPortrait()) {
OneHandedPanel(
panelSide = OneHandedMode.START,
weight = 1f - keyboardWeight,
@@ -626,7 +660,7 @@ class FlorisImeService : LifecycleInputMethodService() {
}
}
}
if (oneHandedMode == OneHandedMode.START && configuration.isOrientationPortrait()) {
if (oneHandedModeEnabled && oneHandedMode == OneHandedMode.START && configuration.isOrientationPortrait()) {
OneHandedPanel(
panelSide = OneHandedMode.END,
weight = 1f - keyboardWeight,
@@ -637,14 +671,6 @@ class FlorisImeService : LifecycleInputMethodService() {
}
}
@Composable
private fun DevtoolsUi() {
val devtoolsEnabled by prefs.devtools.enabled.observeAsState()
if (devtoolsEnabled) {
DevtoolsOverlay(modifier = Modifier.fillMaxSize())
}
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =
if (keyboardManager.onHardwareKeyDown(keyCode, event)) true
else super.onKeyDown(keyCode, event)
@@ -686,12 +712,22 @@ class FlorisImeService : LifecycleInputMethodService() {
ProvideLocalizedResources(resourcesContext, forceLayoutDirection = LayoutDirection.Ltr) {
FlorisImeTheme {
BottomSheetHostUi(
isShowing = state.isBottomSheetShowing(),
isShowing = state.isBottomSheetShowing() || state.isSubtypeSelectionShowing(),
onHide = {
keyboardManager.activeState.isActionsEditorVisible = false
if (state.isBottomSheetShowing()) {
keyboardManager.activeState.isActionsEditorVisible = false
}
if (state.isSubtypeSelectionShowing()) {
keyboardManager.activeState.isSubtypeSelectionVisible = false
}
},
) {
QuickActionsEditorPanel()
if (state.isBottomSheetShowing()) {
QuickActionsEditorPanel()
}
if (state.isSubtypeSelectionShowing()) {
SelectSubtypePanel()
}
}
}
}
@@ -725,44 +761,39 @@ class FlorisImeService : LifecycleInputMethodService() {
@Composable
fun Content() {
val context = LocalContext.current
ProvideLocalizedResources(resourcesContext, forceLayoutDirection = LayoutDirection.Ltr) {
FlorisImeTheme {
val layoutStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputLayout)
val fieldStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputField)
val actionStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputAction)
val activeEditorInfo by editorInstance.activeInfoFlow.collectAsState()
Box(
modifier = Modifier
.snyggBackground(context, layoutStyle, FlorisImeTheme.fallbackSurfaceColor()),
) {
Row(
SnyggBox(FlorisImeUi.ExtractedLandscapeInputLayout.elementName) {
SnyggRow(
modifier = Modifier.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically,
) {
val fieldColor = fieldStyle.foreground.solidColor(context, FlorisImeTheme.fallbackContentColor())
AndroidView(
SnyggBox(
elementName = FlorisImeUi.ExtractedLandscapeInputLayout.elementName,
modifier = Modifier
.padding(8.dp)
.fillMaxHeight()
.weight(1f)
.snyggShadow(fieldStyle)
.snyggBorder(context, fieldStyle)
.snyggBackground(context, fieldStyle),
factory = { extractEditText },
update = { view ->
view.background = null
view.backgroundTintList = null
view.foregroundTintList = null
view.setTextColor(fieldColor.toArgb())
view.setHintTextColor(fieldColor.copy(fieldColor.alpha * 0.6f).toArgb())
view.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
fieldStyle.fontSize.spSize(default = 16.sp).value,
)
},
)
FlorisButton(
.weight(1f),
) {
val fieldStyle = rememberSnyggThemeQuery(FlorisImeUi.ExtractedLandscapeInputField.elementName)
val foreground = fieldStyle.foreground()
AndroidView(
factory = { extractEditText },
update = { view ->
view.background = null
view.backgroundTintList = null
view.foregroundTintList = null
view.setTextColor(foreground.toArgb())
view.setHintTextColor(foreground.copy(foreground.alpha * 0.6f).toArgb())
view.setTextSize(
TypedValue.COMPLEX_UNIT_SP,
fieldStyle.fontSize(default = 16.sp).value,
)
},
)
}
SnyggButton(
FlorisImeUi.ExtractedLandscapeInputAction.elementName,
onClick = {
if (activeEditorInfo.extractedActionId != 0) {
currentInputConnection?.performEditorAction(activeEditorInfo.extractedActionId)
@@ -771,15 +802,13 @@ class FlorisImeService : LifecycleInputMethodService() {
}
},
modifier = Modifier.padding(horizontal = 8.dp),
text = activeEditorInfo.extractedActionLabel
?: getTextForImeAction(activeEditorInfo.imeOptions.action.toInt())
?: "ACTION",
shape = actionStyle.shape.shape(),
colors = ButtonDefaults.buttonColors(
containerColor = actionStyle.background.solidColor(context, FlorisImeTheme.fallbackContentColor()),
contentColor = actionStyle.foreground.solidColor(context, FlorisImeTheme.fallbackSurfaceColor()),
),
)
) {
SnyggText(
text = activeEditorInfo.extractedActionLabel
?: getTextForImeAction(activeEditorInfo.imeOptions.action.toInt())
?: "ACTION",
)
}
}
}
}

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2024 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,10 +18,12 @@ package dev.patrickgold.florisboard.app
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import dev.patrickgold.florisboard.app.settings.theme.DisplayColorsAs
import dev.patrickgold.florisboard.app.settings.theme.DisplayKbdAfterDialogs
import dev.patrickgold.florisboard.app.settings.theme.SnyggLevel
import dev.patrickgold.florisboard.app.setup.NotificationPermissionState
import dev.patrickgold.florisboard.ime.clipboard.CLIPBOARD_HISTORY_NUM_GRID_COLUMNS_AUTO
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.input.CapitalizationBehavior
@@ -40,58 +42,36 @@ 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.QuickAction
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionArrangement
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionJsonConfig
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.key.KeyHintConfiguration
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.ime.theme.ThemeMode
import dev.patrickgold.florisboard.ime.theme.extCoreTheme
import org.florisboard.lib.android.isOrientationPortrait
import dev.patrickgold.florisboard.lib.compose.ColorPreferenceSerializer
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
import dev.patrickgold.florisboard.lib.observeAsTransformingState
import org.florisboard.lib.snygg.SnyggLevel
import dev.patrickgold.florisboard.lib.util.VersionName
import dev.patrickgold.jetpref.datastore.JetPref
import dev.patrickgold.jetpref.datastore.model.LocalTime
import dev.patrickgold.jetpref.datastore.model.PreferenceData
import dev.patrickgold.jetpref.datastore.model.PreferenceMigrationEntry
import dev.patrickgold.jetpref.datastore.model.PreferenceModel
import dev.patrickgold.jetpref.datastore.model.PreferenceType
import dev.patrickgold.jetpref.datastore.model.observeAsState
import kotlinx.serialization.encodeToString
import dev.patrickgold.jetpref.material.ui.ColorRepresentation
import kotlinx.serialization.json.Json
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.isOrientationPortrait
import org.florisboard.lib.color.DEFAULT_GREEN
fun florisPreferenceModel() = JetPref.getOrCreatePreferenceModel(AppPrefs::class, ::AppPrefs)
class AppPrefs : PreferenceModel("florisboard-app-prefs") {
val advanced = Advanced()
inner class Advanced {
val settingsTheme = enum(
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",
)
val showAppIcon = boolean(
key = "advanced__show_app_icon",
default = true,
)
val incognitoMode = enum(
key = "advanced__incognito_mode",
default = IncognitoMode.DYNAMIC_ON_OFF,
)
// Internal pref
val forceIncognitoModeFromDynamic = boolean(
key = "advanced__force_incognito_mode_from_dynamic",
default = false,
)
}
val clipboard = Clipboard()
inner class Clipboard {
val useInternalClipboard = boolean(
@@ -110,6 +90,23 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "clipboard__history_enabled",
default = false,
)
val numHistoryGridColumnsPortrait = int(
key = "clipboard__num_history_grid_columns_portrait",
default = CLIPBOARD_HISTORY_NUM_GRID_COLUMNS_AUTO,
)
val numHistoryGridColumnsLandscape = int(
key = "clipboard__num_history_grid_columns_landscape",
default = CLIPBOARD_HISTORY_NUM_GRID_COLUMNS_AUTO,
)
@Composable
fun numHistoryGridColumns(): PreferenceData<Int> {
val configuration = LocalConfiguration.current
return if (configuration.isOrientationPortrait()) {
numHistoryGridColumnsPortrait
} else {
numHistoryGridColumnsLandscape
}
}
val cleanUpOld = boolean(
key = "clipboard__clean_up_old",
default = false,
@@ -118,6 +115,14 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "clipboard__clean_up_after",
default = 20,
)
val autoCleanSensitive = boolean(
key = "clipboard__auto_clean_sensitive",
default = false,
)
val autoCleanSensitiveAfter = int(
key = "clipboard__auto_clean_sensitive_after",
default = 20,
)
val limitHistorySize = boolean(
key = "clipboard__limit_history_size",
default = true,
@@ -130,6 +135,14 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "clipboard__clear_primary_clip_deletes_last_item",
default = true,
)
val suggestionEnabled = boolean(
key = "clipboard__suggestion_enabled",
default = true,
)
val suggestionTimeout = int(
key = "clipboard__suggestion_timeout",
default = 60,
)
}
val correction = Correction()
@@ -158,10 +171,6 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "devtools__enabled",
default = false,
)
val showHeapMemoryStats = boolean(
key = "devtools__show_heap_memory_stats",
default = false,
)
val showPrimaryClip = boolean(
key = "devtools__show_primary_clip",
default = false,
@@ -494,7 +503,11 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
)
val oneHandedMode = enum(
key = "keyboard__one_handed_mode",
default = OneHandedMode.OFF,
default = OneHandedMode.END,
)
val oneHandedModeEnabled = boolean(
key = "keyboard__one_handed_mode_enabled",
default = false,
)
val oneHandedModeScaleFactor = int(
key = "keyboard__one_handed_mode_scale_factor",
@@ -566,14 +579,14 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
@Composable
fun fontSizeMultiplier(): Float {
val configuration = LocalConfiguration.current
val oneHandedMode by oneHandedMode.observeAsState()
val oneHandedModeEnabled by oneHandedModeEnabled.observeAsState()
val oneHandedModeFactor by oneHandedModeScaleFactor.observeAsTransformingState { it / 100.0f }
val fontSizeMultiplierBase by if (configuration.isOrientationPortrait()) {
fontSizeMultiplierPortrait
} else {
fontSizeMultiplierLandscape
}.observeAsTransformingState { it / 100.0f }
val fontSizeMultiplier = fontSizeMultiplierBase * if (oneHandedMode != OneHandedMode.OFF && configuration.isOrientationPortrait()) {
val fontSizeMultiplier = fontSizeMultiplierBase * if (oneHandedModeEnabled && configuration.isOrientationPortrait()) {
oneHandedModeFactor
} else {
1.0f
@@ -588,6 +601,10 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "localization__display_language_names_in",
default = DisplayLanguageNamesIn.SYSTEM_LOCALE,
)
val displayKeyboardLabelsInSubtypeLanguage = boolean(
key = "localization__display_keyboard_labels_in_subtype_language",
default = false,
)
val activeSubtypeId = long(
key = "localization__active_subtype_id",
default = Subtype.DEFAULT.id,
@@ -598,6 +615,38 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
)
}
val other = Other()
inner class Other {
val settingsTheme = enum(
key = "other__settings_theme",
default = AppTheme.AUTO,
)
val accentColor = custom(
key = "other__accent_color",
default = when (AndroidVersion.ATLEAST_API31_S) {
true -> Color.Unspecified
false -> DEFAULT_GREEN
},
serializer = ColorPreferenceSerializer,
)
val settingsLanguage = string(
key = "other__settings_language",
default = "auto",
)
val showAppIcon = boolean(
key = "other__show_app_icon",
default = true,
)
}
val physicalKeyboard = PhysicalKeyboard()
inner class PhysicalKeyboard {
val showOnScreenKeyboard = boolean(
key = "physical_keyboard__show_on_screen_keyboard",
default = false,
)
}
val smartbar = Smartbar()
inner class Smartbar {
val enabled = boolean(
@@ -674,13 +723,14 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
key = "suggestion__block_possibly_offensive",
default = true,
)
val clipboardContentEnabled = boolean(
key = "suggestion__clipboard_content_enabled",
default = true,
val incognitoMode = enum(
key = "suggestion__incognito_mode",
default = IncognitoMode.DYNAMIC_ON_OFF,
)
val clipboardContentTimeout = int(
key = "suggestion__clipboard_content_timeout",
default = 60,
// Internal pref
val forceIncognitoModeFromDynamic = boolean(
key = "suggestion__force_incognito_mode_from_dynamic",
default = false,
)
}
@@ -700,17 +750,25 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
default = extCoreTheme("floris_night"),
serializer = ExtensionComponentName.Serializer,
)
//val sunriseTime = localTime(
// key = "theme__sunrise_time",
// default = LocalTime.of(6, 0),
//)
//val sunsetTime = localTime(
// key = "theme__sunset_time",
// default = LocalTime.of(18, 0),
//)
val editorDisplayColorsAs = enum(
key = "theme__editor_display_colors_as",
default = DisplayColorsAs.HEX8,
val accentColor = custom(
key = "theme__accent_color",
default = when (AndroidVersion.ATLEAST_API31_S) {
true -> Color.Unspecified
false -> DEFAULT_GREEN
},
serializer = ColorPreferenceSerializer,
)
val sunriseTime = time(
key = "theme__sunrise_time",
default = LocalTime(6, 0),
)
val sunsetTime = time(
key = "theme__sunset_time",
default = LocalTime(18, 0),
)
val editorColorRepresentation = enum(
key = "theme__editor_color_representation",
default = ColorRepresentation.HEX,
)
val editorDisplayKbdAfterDialogs = enum(
key = "theme__editor_display_kbd_after_dialogs",
@@ -724,34 +782,6 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
override fun migrate(entry: PreferenceMigrationEntry): PreferenceMigrationEntry {
return when (entry.key) {
// Migrate enums from their lowercase to uppercase representation
// Keep migration rule until: 0.5 dev cycle
"advanced__settings_theme", "gestures__swipe_up", "gestures__swipe_down", "gestures__swipe_left",
"gestures__swipe_right", "gestures__space_bar_swipe_up", "gestures__space_bar_swipe_left",
"gestures__space_bar_swipe_right", "gestures__space_bar_long_press", "gestures__delete_key_swipe_left",
"gestures__delete_key_long_press", "keyboard__hinted_number_row_mode", "keyboard__hinted_symbols_mode",
"keyboard__utility_key_action", "keyboard__one_handed_mode", "keyboard__landscape_input_ui_mode",
"localization__display_language_names_in", "smartbar__primary_actions_row_type",
"smartbar__secondary_actions_placement", "smartbar__secondary_actions_row_type", "spelling__language_mode",
"suggestion__display_mode", "theme__mode", "theme__editor_display_colors_as",
"theme__editor_display_kbd_after_dialogs", "theme__editor_level",
-> {
entry.transform(rawValue = entry.rawValue.uppercase())
}
// Migrate old private mode force flag as this is a sensitive preference
// Keep migration rule until: 0.5 dev cycle
"advanced__force_private_mode" -> {
if (entry.rawValue.toBoolean()) {
entry.transform(
type = PreferenceType.string(),
key = "advanced__incognito_mode",
rawValue = IncognitoMode.FORCE_ON.toString(),
)
} else {
entry.reset()
}
}
// Migrate media prefs to emoji prefs
// Keep migration rule until: 0.6 dev cycle
@@ -766,19 +796,82 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
"media__emoji_recently_used_max_size" -> {
entry.transform(key = "emoji__history_recent_max_size")
}
"media__emoji_preferred_skin_tone" -> {
// Migrate advanced prefs to other prefs
// Keep migration rules until: 0.7 dev cycle
"advanced__settings_theme" -> {
entry.transform(key = "other__settings_theme")
}
"advanced__accent_color" -> {
entry.transform(key = "other__accent_color")
}
"advanced__settings_language" -> {
entry.transform(key = "other__settings_language")
}
"advanced__show_app_icon" -> {
entry.transform(key = "other__show_app_icon")
}
"advanced__incognito_mode" -> {
entry.transform(key = "suggestion__incognito_mode")
}
"advanced__force_incognito_mode_from_dynamic" -> {
entry.transform(key = "suggestion__force_incognito_mode_from_dynamic")
}
// Migrate clipboard suggestion prefs to clipboard
// Keep migration rules until: 0.7 dev cycle
"suggestion__clipboard_content_enabled" -> {
entry.transform(key = "clipboard__suggestion_enabled")
}
"suggestion__clipboard_content_timeout" -> {
entry.transform(key = "clipboard__suggestion_timeout")
}
//Migrate one hand mode prefs keep until: 0.7 dev cycle
"keyboard__one_handed_mode" -> {
if (entry.rawValue == "OFF") {
entry.reset()
} else {
entry.keepAsIs()
}
}
"smartbar__action_arrangement" -> {
fun migrateAction(action: QuickAction): QuickAction {
return if (action is QuickAction.InsertKey && action.data.code == KeyCode.COMPACT_LAYOUT_TO_RIGHT) {
action.copy(TextKeyData.TOGGLE_COMPACT_LAYOUT)
} else {
action
}
}
val arrangement = QuickActionJsonConfig.decodeFromString<QuickActionArrangement>(entry.rawValue)
var newArrangement = arrangement.copy(
stickyAction = arrangement.stickyAction?.let{ migrateAction(it) },
dynamicActions = arrangement.dynamicActions.map { migrateAction(it) },
hiddenActions = arrangement.hiddenActions.map { migrateAction(it) },
)
if (QuickAction.InsertKey(TextKeyData.LANGUAGE_SWITCH) !in newArrangement) {
newArrangement = newArrangement.copy(
dynamicActions = newArrangement.dynamicActions.plus(QuickAction.InsertKey(TextKeyData.LANGUAGE_SWITCH))
)
}
val json = QuickActionJsonConfig.encodeToString(newArrangement.distinct())
entry.transform(rawValue = json)
}
// Migrate theme editor fine-tuning
// Keep migration rule until: 0.6 dev cycle
"theme__editor_display_colors_as" -> {
val colorRepresentation = when (entry.rawValue) {
"RGBA" -> ColorRepresentation.RGB
else -> ColorRepresentation.HEX
}
entry.transform(
key = "emoji__preferred_skin_tone",
rawValue = entry.rawValue.uppercase(), // keep until: 0.5 dev cycle
)
}
"media__emoji_preferred_hair_style" -> {
entry.transform(
key = "emoji__preferred_hair_style",
rawValue = entry.rawValue.uppercase(), // keep until: 0.5 dev cycle
key = "theme__editor_color_representation",
rawValue = colorRepresentation.name,
)
}
// Default: keep entry
else -> entry.keepAsIs()
}

View File

@@ -1,14 +1,32 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app
import androidx.compose.runtime.Composable
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.app.settings.theme.SnyggLevel
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.input.InputShiftState
import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
import dev.patrickgold.florisboard.ime.keyboard.KeyboardMode
import dev.patrickgold.florisboard.ime.keyboard.SpaceBarMode
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHistory
@@ -25,9 +43,9 @@ 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 dev.patrickgold.jetpref.material.ui.ColorRepresentation
import org.florisboard.lib.kotlin.curlyFormat
import kotlin.reflect.KClass
@@ -42,19 +60,19 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
)
entry(
key = AppTheme.AUTO_AMOLED,
label = stringRes(R.string.pref__advanced__settings_theme__auto_amoled),
label = stringRes(R.string.pref__other__settings_theme__auto_amoled),
)
entry(
key = AppTheme.LIGHT,
label = stringRes(R.string.pref__advanced__settings_theme__light),
label = stringRes(R.string.pref__other__settings_theme__light),
)
entry(
key = AppTheme.DARK,
label = stringRes(R.string.pref__advanced__settings_theme__dark),
label = stringRes(R.string.pref__other__settings_theme__dark),
)
entry(
key = AppTheme.AMOLED_DARK,
label = stringRes(R.string.pref__advanced__settings_theme__amoled_dark),
label = stringRes(R.string.pref__other__settings_theme__amoled_dark),
)
}
},
@@ -86,18 +104,24 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
)
}
},
DisplayColorsAs::class to DEFAULT to {
ColorRepresentation::class to DEFAULT to {
listPrefEntries {
entry(
key = DisplayColorsAs.HEX8,
label = stringRes(R.string.enum__display_colors_as__hex8),
key = ColorRepresentation.HEX,
label = stringRes(R.string.enum__color_representation__hex),
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)"),
key = ColorRepresentation.RGB,
label = stringRes(R.string.enum__color_representation__rgb),
description = stringRes(R.string.general__example_given).curlyFormat("example" to "rgba(76, 175, 80, 1.0)"),
showDescriptionOnlyIfSelected = true,
)
entry(
key = ColorRepresentation.HSV,
label = stringRes(R.string.enum__color_representation__hsv),
description = stringRes(R.string.general__example_given).curlyFormat("example" to "hsva(122, 56, 68, 1.0)"),
showDescriptionOnlyIfSelected = true,
)
}
@@ -342,6 +366,58 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
)
}
},
InputShiftState::class to DEFAULT to {
listPrefEntries {
entry(
key = InputShiftState.UNSHIFTED,
label = stringRes(R.string.enum__input_shift_state__unshifted),
)
entry(
key = InputShiftState.SHIFTED_MANUAL,
label = stringRes(R.string.enum__input_shift_state__shifted_manual),
)
entry(
key = InputShiftState.SHIFTED_AUTOMATIC,
label = stringRes(R.string.enum__input_shift_state__shifted_automatic),
)
entry(
key = InputShiftState.CAPS_LOCK,
label = stringRes(R.string.enum__input_shift_state__caps_lock),
)
}
},
KeyboardMode::class to DEFAULT to {
listPrefEntries {
entry(
key = KeyboardMode.CHARACTERS,
label = stringRes(R.string.enum__keyboard_mode__characters),
)
entry(
key = KeyboardMode.SYMBOLS,
label = stringRes(R.string.enum__keyboard_mode__symbols),
)
entry(
key = KeyboardMode.SYMBOLS2,
label = stringRes(R.string.enum__keyboard_mode__symbols2),
)
entry(
key = KeyboardMode.NUMERIC,
label = stringRes(R.string.enum__keyboard_mode__numeric),
)
entry(
key = KeyboardMode.NUMERIC_ADVANCED,
label = stringRes(R.string.enum__keyboard_mode__numeric_advanced),
)
entry(
key = KeyboardMode.PHONE,
label = stringRes(R.string.enum__keyboard_mode__phone),
)
entry(
key = KeyboardMode.PHONE2,
label = stringRes(R.string.enum__keyboard_mode__phone2),
)
}
},
LandscapeInputUiMode::class to DEFAULT to {
listPrefEntries {
entry(
@@ -360,10 +436,6 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
},
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),
@@ -526,6 +598,10 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
key = SwipeAction.SHOW_INPUT_METHOD_PICKER,
label = stringRes(R.string.enum__swipe_action__show_input_method_picker),
)
entry(
key = SwipeAction.SHOW_SUBTYPE_PICKER,
label = "Show subtype picker"
)
entry(
key = SwipeAction.SWITCH_TO_PREV_SUBTYPE,
label = stringRes(R.string.enum__swipe_action__switch_to_prev_subtype),

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -88,17 +88,17 @@ class FlorisAppActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
prefs.advanced.settingsTheme.observe(this) {
prefs.other.settingsTheme.observe(this) {
appTheme = it
}
prefs.advanced.settingsLanguage.observe(this) {
prefs.other.settingsLanguage.observe(this) {
val config = Configuration(resources.configuration)
val locale = if (it == "auto") FlorisLocale.default() else FlorisLocale.fromTag(it)
config.setLocale(locale.base)
resourcesContext = createConfigurationContext(config)
}
if (AndroidVersion.ATMOST_API28_P) {
prefs.advanced.showAppIcon.observe(this) {
prefs.other.showAppIcon.observe(this) {
showAppIcon = it
}
}
@@ -117,8 +117,7 @@ class FlorisAppActivity : ComponentActivity() {
AppVersionUtils.updateVersionOnInstallAndLastUse(this, prefs)
setContent {
ProvideLocalizedResources(resourcesContext) {
val useMaterialYou by prefs.advanced.useMaterialYou.observeAsState()
FlorisAppTheme(theme = appTheme, isMaterialYouAware = useMaterialYou) {
FlorisAppTheme(theme = appTheme) {
Surface(color = MaterialTheme.colorScheme.background) {
AppContent()
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,8 +47,9 @@ import dev.patrickgold.florisboard.app.settings.HomeScreen
import dev.patrickgold.florisboard.app.settings.about.AboutScreen
import dev.patrickgold.florisboard.app.settings.about.ProjectLicenseScreen
import dev.patrickgold.florisboard.app.settings.about.ThirdPartyLicensesScreen
import dev.patrickgold.florisboard.app.settings.advanced.AdvancedScreen
import dev.patrickgold.florisboard.app.settings.advanced.BackupScreen
import dev.patrickgold.florisboard.app.settings.advanced.OtherScreen
import dev.patrickgold.florisboard.app.settings.advanced.PhysicalKeyboardScreen
import dev.patrickgold.florisboard.app.settings.advanced.RestoreScreen
import dev.patrickgold.florisboard.app.settings.clipboard.ClipboardScreen
import dev.patrickgold.florisboard.app.settings.dictionary.DictionaryScreen
@@ -110,9 +111,10 @@ object Routes {
const val Media = "settings/media"
const val Advanced = "settings/advanced"
const val Backup = "settings/advanced/backup"
const val Restore = "settings/advanced/restore"
const val Other = "settings/other"
const val PhysicalKeyboard = "settings/other/physical-keyboard"
const val Backup = "settings/other/backup"
const val Restore = "settings/other/restore"
const val About = "settings/about"
const val ProjectLicense = "settings/about/project-license"
@@ -239,7 +241,8 @@ object Routes {
composableWithDeepLink(Settings.Media) { MediaScreen() }
composableWithDeepLink(Settings.Advanced) { AdvancedScreen() }
composableWithDeepLink(Settings.Other) { OtherScreen() }
composableWithDeepLink(Settings.PhysicalKeyboard) { PhysicalKeyboardScreen() }
composableWithDeepLink(Settings.Backup) { BackupScreen() }
composableWithDeepLink(Settings.Restore) { RestoreScreen() }

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,19 +17,22 @@
package dev.patrickgold.florisboard.app.apptheme
import android.app.Activity
import android.content.Context
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
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.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import dev.patrickgold.florisboard.app.AppTheme
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.jetpref.datastore.model.observeAsState
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.color.ColorMappings
/*private val AmoledDarkColorPalette = darkColorScheme(
primary = Green500,
@@ -70,170 +73,66 @@ private val LightColorPalette = lightColorScheme(
*/
)*/
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,
)
@Composable
fun getColorScheme(
context: Context,
theme: AppTheme,
): ColorScheme {
val prefs by florisPreferenceModel()
val accentColor by prefs.other.accentColor.observeAsState()
val isDark = isSystemInDarkTheme()
private val amoledScheme = darkScheme.copy(
background = amoledDark,
surface = amoledDark
)
return when (theme) {
AppTheme.AUTO -> {
if (isDark) {
ColorMappings.dynamicDarkColorScheme(context, accentColor)
} else {
ColorMappings.dynamicLightColorScheme(context, accentColor)
}
}
AppTheme.DARK -> {
ColorMappings.dynamicDarkColorScheme(context, accentColor)
}
AppTheme.LIGHT -> {
ColorMappings.dynamicLightColorScheme(context, accentColor)
}
AppTheme.AMOLED_DARK -> {
ColorMappings.dynamicDarkColorScheme(context, accentColor).amoled()
}
AppTheme.AUTO_AMOLED -> {
if (isDark) {
ColorMappings.dynamicDarkColorScheme(context, accentColor).amoled()
} else {
ColorMappings.dynamicLightColorScheme(context, accentColor)
}
}
}
}
fun ColorScheme.amoled(): ColorScheme {
return this.copy(background = Color.Black, surface = Color.Black)
}
@Composable
fun FlorisAppTheme(
theme: AppTheme,
isMaterialYouAware: Boolean,
content: @Composable () -> Unit
content: @Composable () -> Unit,
) {
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
}
}
} 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 colors = getColorScheme(
context = LocalContext.current,
theme = theme,
)
val darkTheme =
theme == AppTheme.DARK
|| theme == AppTheme.AMOLED_DARK
|| (theme == AppTheme.AUTO && isSystemInDarkTheme())
|| (theme == AppTheme.AUTO_AMOLED && isSystemInDarkTheme())
|| theme == AppTheme.AMOLED_DARK
|| (theme == AppTheme.AUTO && isSystemInDarkTheme())
|| (theme == AppTheme.AUTO_AMOLED && isSystemInDarkTheme())
val view = LocalView.current
if (!view.isInEditMode) {

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -42,12 +43,18 @@ import androidx.compose.ui.unit.sp
import dev.patrickgold.florisboard.app.florisPreferenceModel
import dev.patrickgold.florisboard.clipboardManager
import dev.patrickgold.florisboard.editorInstance
import dev.patrickgold.florisboard.ime.keyboard.CachedLayout
import dev.patrickgold.florisboard.ime.keyboard.DebugLayoutComputationResult
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.keyboardManager
import dev.patrickgold.florisboard.lib.FlorisLocale
import dev.patrickgold.florisboard.lib.observeAsNonNullState
import dev.patrickgold.florisboard.nlpManager
import dev.patrickgold.florisboard.themeManager
import dev.patrickgold.jetpref.datastore.model.observeAsState
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.snygg.SnyggMissingSchemaException
import java.text.SimpleDateFormat
import java.util.*
@@ -56,30 +63,44 @@ private val DateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", FlorisLocale.
@Composable
fun DevtoolsOverlay(modifier: Modifier = Modifier) {
val context = LocalContext.current
val prefs by florisPreferenceModel()
val keyboardManager by context.keyboardManager()
val themeManager by context.themeManager()
val devtoolsEnabled by prefs.devtools.enabled.observeAsState()
val showPrimaryClip by prefs.devtools.showPrimaryClip.observeAsState()
val showInputStateOverlay by prefs.devtools.showInputStateOverlay.observeAsState()
val showSpellingOverlay by prefs.devtools.showSpellingOverlay.observeAsState()
val showInlineAutofillOverlay by prefs.devtools.showInlineAutofillOverlay.observeAsState()
val debugLayoutResult by keyboardManager.layoutManager.debugLayoutComputationResultFlow.collectAsState()
val themeInfo by themeManager.activeThemeInfo.observeAsState()
CompositionLocalProvider(
LocalContentColor provides Color.White,
LocalLayoutDirection provides LayoutDirection.Ltr,
) {
Column(modifier = modifier) {
if (showPrimaryClip) {
if (devtoolsEnabled && showPrimaryClip) {
DevtoolsClipboardOverlay()
}
if (showInputStateOverlay) {
if (devtoolsEnabled && showInputStateOverlay) {
DevtoolsInputStateOverlay()
}
if (showSpellingOverlay) {
if (debugLayoutResult?.allLayoutsSuccess() == false) {
DevtoolsLastLayoutComputationOverlay(debugLayoutResult)
}
if (devtoolsEnabled && showSpellingOverlay) {
DevtoolsSpellingOverlay()
}
if (showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
if (devtoolsEnabled && showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
DevtoolsInlineAutofillOverlay()
}
val loadFailure = themeInfo?.loadFailure
if (loadFailure != null) {
DevtoolsStylesheetFailedToLoadOverlay(loadFailure)
}
}
}
}
@@ -125,6 +146,34 @@ private fun DevtoolsInputStateOverlay() {
}
}
@Composable
private fun DevtoolsLastLayoutComputationOverlay(debugLayoutResult: DebugLayoutComputationResult?) {
@Composable
fun PrintResult(result: Result<CachedLayout?>) {
if (result.isSuccess) {
DevtoolsText(text = "loaded: ${result.getOrNull()?.name}")
} else {
DevtoolsText(text = "error: ${result.exceptionOrNull()}")
}
}
DevtoolsOverlayBox(title = "Last layout computation") {
if (debugLayoutResult == null) {
DevtoolsText(text = "No layout computation result available.")
return@DevtoolsOverlayBox
}
DevtoolsSubGroup(title = "main") {
PrintResult(debugLayoutResult!!.main)
}
DevtoolsSubGroup(title = "mod") {
PrintResult(debugLayoutResult!!.mod)
}
DevtoolsSubGroup(title = "ext") {
PrintResult(debugLayoutResult!!.ext)
}
}
}
@Composable
private fun DevtoolsSpellingOverlay() {
val context = LocalContext.current
@@ -186,6 +235,39 @@ private fun DevtoolsInlineAutofillOverlay() {
}
}
@Composable
private fun DevtoolsStylesheetFailedToLoadOverlay(loadFailure: ThemeManager.LoadFailure) {
DevtoolsOverlayBox(title = "Failed to load stylesheet, fell back to base style") {
DevtoolsSubGroup(title = "Extension") {
DevtoolsText(text = "id: ${loadFailure.extension.id}")
DevtoolsText(text = "title: ${loadFailure.extension.title}")
DevtoolsText(text = "version: ${loadFailure.extension.version}")
}
DevtoolsSubGroup(title = "Component") {
DevtoolsText(text = "id: ${loadFailure.component.id}")
DevtoolsText(text = "label: ${loadFailure.component.label}")
DevtoolsText(text = "path: ${loadFailure.component.stylesheetPath()}")
}
val cause = loadFailure.cause
DevtoolsSubGroup(title = "Cause") {
DevtoolsText(text = "${cause.message}")
}
if (cause is SnyggMissingSchemaException) {
DevtoolsSubGroup(title = "Explanation") {
DevtoolsText(
text = """
It appears youre trying to load a theme designed for FlorisBoard v0.4 (Snygg v1), which isnt compatible with the latest release using Snygg v2.
If you are the theme author, please update your theme to support Snygg v2.
If youre a user, please update your theme via the Addons Store. If an updated version isnt available yet, please select one of the built-in themes during this transition period.
""".trimIndent()
)
}
}
}
}
@Composable
private fun DevtoolsOverlayBox(
title: String,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +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.ime.smartbar.quickaction.QuickActionArrangement
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionJsonConfig
import org.florisboard.lib.android.AndroidSettings
import org.florisboard.lib.android.showLongToast
import dev.patrickgold.florisboard.lib.compose.FlorisConfirmDeleteDialog
@@ -61,12 +63,6 @@ fun DevtoolsScreen() = FlorisScreen {
)
PreferenceGroup(title = stringRes(R.string.devtools__title)) {
SwitchPreference(
prefs.devtools.showHeapMemoryStats,
title = stringRes(R.string.devtools__show_heap_memory_stats__label),
summary = stringRes(R.string.devtools__show_heap_memory_stats__summary),
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
SwitchPreference(
prefs.devtools.showPrimaryClip,
title = stringRes(R.string.devtools__show_primary_clip__label),
@@ -110,6 +106,15 @@ fun DevtoolsScreen() = FlorisScreen {
onClick = { setShowDialog(true) },
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
Preference(
title = stringRes(R.string.devtools__reset_quick_actions_to_default__label),
summary = stringRes(R.string.devtools__reset_quick_actions_to_default__summary),
onClick = {
prefs.smartbar.actionArrangement.set(QuickActionArrangement.Default)
context.showLongToast(R.string.devtools__reset_quick_actions_to_default__toast_success)
},
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
Preference(
title = stringRes(R.string.devtools__reset_flag__label, "flag_name" to "isImeSetUp"),
summary = stringRes(R.string.devtools__reset_flag_is_ime_set_up__summary),
@@ -128,6 +133,13 @@ fun DevtoolsScreen() = FlorisScreen {
onClick = { navController.navigate(Routes.Devtools.ExportDebugLog) },
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
SwitchPreference(
prefs.glide.enabled,
title = "prefs.glide.enabled (debug)",
summaryOn = "This impacts your performance and may trigger the all keys invisible bug!",
summaryOff = "Recommended to keep this off!",
enabledIf = { prefs.devtools.enabled isEqualTo true },
)
}
PreferenceGroup(title = stringRes(R.string.devtools__group_android__title)) {

View File

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

View File

@@ -1,3 +1,19 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Row
@@ -5,6 +21,7 @@ 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.Shop
import androidx.compose.material.icons.outlined.FileDownload
import androidx.compose.material3.MaterialTheme
@@ -13,6 +30,8 @@ import androidx.compose.runtime.Composable
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.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.Routes
@@ -25,6 +44,41 @@ import dev.patrickgold.florisboard.lib.ext.generateUpdateUrl
import dev.patrickgold.florisboard.lib.util.launchUrl
import org.florisboard.lib.kotlin.curlyFormat
@Composable
fun ImportExtensionBox(navController: NavController) {
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__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),
)
}
}
}
@Composable
fun UpdateBox(extensionIndex: List<Extension>) {
val context = LocalContext.current

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 Patrick Goldinger
* Copyright (C) 2022-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,14 +81,11 @@ fun ExtensionComponentView(
when (component) {
is ThemeExtensionComponent -> {
val text = remember(
component.authors, component.isNightTheme, component.isBorderless,
component.isMaterialYouAware, component.stylesheetPath(),
component.authors, component.isNightTheme, component.stylesheetPath(),
) {
buildString {
appendLine("authors = ${component.authors}")
appendLine("isNightTheme = ${component.isNightTheme}")
appendLine("isBorderless = ${component.isBorderless}")
appendLine("isMaterialYouAware = ${component.isMaterialYouAware}")
append("stylesheetPath = ${component.stylesheetPath()}")
}
}

View File

@@ -0,0 +1,290 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.ext
import android.provider.OpenableColumns
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
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.Photo
import androidx.compose.material.icons.filled.TextFields
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
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.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.cache.CacheManager
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import dev.patrickgold.jetpref.material.ui.JetPrefTextField
import java.io.File
import java.util.*
import org.florisboard.lib.android.query
import org.florisboard.lib.android.readToFile
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.android.showShortToast
import org.florisboard.lib.kotlin.io.parentDir
import org.florisboard.lib.kotlin.io.subDir
import org.florisboard.lib.kotlin.io.subFile
import org.florisboard.lib.kotlin.mimeTypeFilterOf
const val FONTS = "fonts"
const val IMAGES = "images"
val MIME_TYPES = mapOf(
FONTS to mimeTypeFilterOf(
// Source: https://www.alienfactory.co.uk/articles/mime-types-for-web-fonts-in-bedsheet#mimeTypes
"font/*",
"application/font-*",
"application/x-font-*",
"application/vnd.ms-fontobject",
),
IMAGES to mimeTypeFilterOf(
"image/*",
),
)
@Composable
fun ExtensionEditFilesScreen(workspace: CacheManager.ExtEditorWorkspace<*>) = FlorisScreen {
title = stringRes(R.string.ext__editor__files__title)
fun handleBackPress() {
workspace.currentAction = null
}
navigationIcon {
FlorisIconButton(
onClick = { handleBackPress() },
icon = Icons.Default.Close,
)
}
content {
val context = LocalContext.current
var version by rememberSaveable { mutableIntStateOf(0) }
val fontFiles = remember(version) {
workspace.extDir.subDir(FONTS).listFiles { it.isFile }.orEmpty().asList()
}
val imageFiles = remember(version) {
workspace.extDir.subDir(IMAGES).listFiles { it.isFile }.orEmpty().asList()
}
var currentImportDest by remember { mutableStateOf<String?>(null) }
var currentImportResult by remember { mutableStateOf<Result<Pair<File, String>>?>(null) }
val importLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent(),
onResult = { uri ->
currentImportResult = runCatching {
checkNotNull(uri) { "" }
val tempFile = context.cacheDir.subFile("temp_${UUID.randomUUID()}")
context.contentResolver.readToFile(uri, tempFile)
val mimeType = context.contentResolver.getType(uri)
val filter = MIME_TYPES[currentImportDest!!]!!
check(filter.matches(mimeType)) {
"Given file mime type was '$mimeType', expected one of ${filter.types}"
}
val fileName = context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME)).use { cursor ->
if (cursor == null || !cursor.moveToFirst()) return@use null
val name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
cursor.getString(name)
}
tempFile to fileName.orEmpty()
}
},
)
LaunchedEffect(currentImportResult) {
val message = currentImportResult?.exceptionOrNull()?.message
if (!message.isNullOrBlank()) {
context.showLongToast(message)
}
}
BackHandler {
handleBackPress()
}
@Composable
fun FileList(title: String, icon: ImageVector, files: List<File>, onAdd: () -> Unit) {
var dialogFile by remember { mutableStateOf<File?>(null) }
ListItem(
headlineContent = {
Text(
text = title,
color = MaterialTheme.colorScheme.secondary,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
},
leadingContent = {
Spacer(modifier = Modifier.width(24.dp))
},
trailingContent = {
IconButton(
onClick = onAdd,
) {
Icon(Icons.Default.Add, null)
}
},
)
for (file in files) {
Preference(
onClick = {
dialogFile = file
},
icon = icon,
title = file.name,
)
}
dialogFile?.let { file ->
var fileNameInput by rememberSaveable { mutableStateOf(file.name) }
JetPrefAlertDialog(
title = stringRes(R.string.general__properties),
confirmLabel = stringRes(R.string.action__apply),
dismissLabel = stringRes(R.string.action__cancel),
neutralLabel = stringRes(R.string.action__delete),
allowOutsideDismissal = true,
onNeutral = {
if (file.delete()) {
context.showShortToast("Successfully deleted")
} else {
context.showShortToast("Failed to delete")
}
dialogFile = null
version++
},
onConfirm = {
val newFile = file.parentFile!!.subFile(fileNameInput).canonicalFile
if (newFile.parentFile != file.canonicalFile.parentFile) {
context.showLongToast("Invalid file name!")
return@JetPrefAlertDialog
}
if (newFile.exists()) {
context.showShortToast("Filename already exists.")
return@JetPrefAlertDialog
}
val success = file.renameTo(newFile)
if (success) {
context.showShortToast("Successfully renamed")
} else {
context.showShortToast("Failed to rename the file.")
}
dialogFile = null
version++
},
onDismiss = {
dialogFile = null
},
) {
JetPrefTextField(
labelText = stringRes(R.string.general__file_name),
value = fileNameInput,
onValueChange = { fileNameInput = it },
singleLine = true,
)
}
}
}
FileList(
title = stringRes(R.string.ext__editor__files__type_fonts),
icon = Icons.Default.TextFields,
files = fontFiles,
) {
currentImportDest = FONTS
importLauncher.launch("*/*")
}
FileList(
title = stringRes(R.string.ext__editor__files__type_images),
icon = Icons.Default.Photo,
files = imageFiles,
) {
currentImportDest = IMAGES
importLauncher.launch("*/*")
}
val dest = currentImportDest
val result = currentImportResult?.getOrNull()
if (dest != null && result != null) {
var fileNameInput by rememberSaveable { mutableStateOf(result.second) }
JetPrefAlertDialog(
title = stringRes(R.string.action__import_file),
confirmLabel = stringRes(R.string.action__add),
onConfirm = {
val fileName = fileNameInput.trim()
val dir = workspace.extDir.subDir(dest)
dir.mkdirs()
val file = dir.subFile(fileName)
if (file.parentDir != workspace.extDir.subDir(dest)) {
context.showShortToast("Invalid file name")
} else if (file.exists()) {
context.showShortToast("File already exists")
} else {
val tempFile = result.first
if (!tempFile.renameTo(file)) {
context.showShortToast("Failed to rename file")
tempFile.delete()
}
currentImportDest = null
currentImportResult = null
version++
}
},
dismissLabel = stringRes(R.string.action__cancel),
onDismiss = {
val tempFile = result.first
tempFile.delete()
currentImportDest = null
currentImportResult = null
},
) {
JetPrefTextField(
value = fileNameInput,
onValueChange = { fileNameInput = it },
singleLine = true,
)
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ import androidx.compose.material.icons.automirrored.outlined.LibraryBooks
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Code
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
@@ -49,6 +48,7 @@ import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.app.LocalNavController
import dev.patrickgold.florisboard.app.settings.advanced.RadioListItem
import dev.patrickgold.florisboard.app.settings.theme.DialogProperty
import dev.patrickgold.florisboard.app.settings.theme.PrettyPrintConfig
import dev.patrickgold.florisboard.app.settings.theme.ThemeEditorScreen
import dev.patrickgold.florisboard.cacheManager
import dev.patrickgold.florisboard.extensionManager
@@ -64,9 +64,9 @@ import dev.patrickgold.florisboard.lib.compose.FlorisButtonBar
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
import dev.patrickgold.florisboard.lib.compose.FlorisInfoCard
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedTextField
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.FlorisUnsavedChangesDialog
import dev.patrickgold.florisboard.lib.compose.Validation
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.florisboard.lib.ext.Extension
@@ -83,15 +83,17 @@ 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.rememberValidationResult
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 dev.patrickgold.jetpref.material.ui.JetPrefTextField
import java.util.*
import org.florisboard.lib.android.showLongToast
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
import org.florisboard.lib.kotlin.io.subDir
import org.florisboard.lib.kotlin.io.subFile
import org.florisboard.lib.kotlin.io.writeJson
import java.util.UUID
import kotlin.reflect.KClass
private val TextFieldVerticalPadding = 8.dp
@@ -197,7 +199,7 @@ private fun ExtensionEditScreenSheetSwitcher(
ManageDependenciesScreen(workspace)
}
is EditorAction.ManageFiles -> {
ManageFilesScreen(workspace)
ExtensionEditFilesScreen(workspace)
}
is EditorAction.CreateComponent<*> -> {
CreateComponentScreen(workspace, action.type)
@@ -261,17 +263,33 @@ private fun EditScreen(
return
}
val manifest = extEditor.build()
workspace.saverDir.deleteContentsRecursively()
val manifestFile = workspace.saverDir.subFile(ExtensionDefaults.MANIFEST_FILE_NAME)
manifestFile.writeJson(manifest, ExtensionJsonConfig)
when (extEditor) {
is ThemeExtensionEditor -> {
// TODO: this is hacky
val fonts = workspace.extDir.subDir("fonts")
if (fonts.exists()) {
fonts.copyRecursively(workspace.saverDir.subDir("fonts"), overwrite = true)
}
val images = workspace.extDir.subDir("images")
if (images.exists()) {
images.copyRecursively(workspace.saverDir.subDir("images"), overwrite = true)
}
for (theme in extEditor.themes) {
val stylesheetFile = workspace.saverDir.subFile(theme.stylesheetPath())
stylesheetFile.parentFile?.mkdirs()
val stylesheetEditor = theme.stylesheetEditor
if (stylesheetEditor != null) {
val stylesheet = stylesheetEditor.build()
stylesheetFile.writeJson(stylesheet, SnyggStylesheetJsonConfig)
runCatching {
val stylesheet = stylesheetEditor.build().toJson(PrettyPrintConfig).getOrThrow()
stylesheetFile.writeText(stylesheet)
}.onFailure {
// TODO: better error handling
context.showLongToast(it.message.toString())
return
}
} else {
val unmodifiedStylesheetFile = workspace.extDir.subFile(theme.stylesheetPath())
if (unmodifiedStylesheetFile.exists()) {
@@ -582,35 +600,6 @@ private fun ManageDependenciesScreen(workspace: CacheManager.ExtEditorWorkspace<
}
}
@Composable
private fun ManageFilesScreen(workspace: CacheManager.ExtEditorWorkspace<*>) = FlorisScreen {
title = stringRes(R.string.ext__editor__files__title)
fun handleBackPress() {
workspace.currentAction = null
}
navigationIcon {
FlorisIconButton(
onClick = { handleBackPress() },
icon = Icons.Default.Close,
)
}
content {
BackHandler {
handleBackPress()
}
FlorisInfoCard(
modifier = Modifier.padding(all = 8.dp),
text = """
Managing archive files is currently not supported.
""".trimIndent().replace('\n', ' '),
)
}
}
private enum class CreateFrom {
EMPTY,
EXISTING;
@@ -703,15 +692,14 @@ private fun <T : ExtensionComponent> CreateComponentScreen(
val component = editor.themes.find { it.id == componentName.componentId } ?: return
val componentEditor = component.let { c ->
ThemeExtensionComponentEditor(
componentId, c.label, c.authors, c.isNightTheme, c.isBorderless,
c.isMaterialYouAware, stylesheetPath = "",
componentId, c.label, c.authors, c.isNightTheme, stylesheetPath = "",
).also { it.stylesheetEditor = c.stylesheetEditor }
}
if (componentEditor.stylesheetEditor != null) {
val stylesheet = componentEditor.stylesheetEditor!!.build()
val stylesheetFile = workspace.extDir.subFile(componentEditor.stylesheetPath())
stylesheetFile.parentFile?.mkdirs()
stylesheetFile.writeJson(stylesheet, SnyggStylesheetJsonConfig)
val stylesheet = componentEditor.stylesheetEditor!!.build().toJson(PrettyPrintConfig).getOrThrow()
stylesheetFile.writeText(stylesheet)
componentEditor.stylesheetEditor = null
} else {
val srcStylesheetFile = workspace.extDir.subFile(component.stylesheetPath())
@@ -813,36 +801,37 @@ private fun <T : ExtensionComponent> CreateComponentScreen(
modifier = Modifier.padding(horizontal = 16.dp),
text = stringRes(R.string.ext__meta__id),
) {
FlorisOutlinedTextField(
JetPrefTextField(
modifier = Modifier.fillMaxWidth(),
value = newId,
onValueChange = { newId = it },
singleLine = true,
showValidationError = showValidationErrors,
validationResult = newIdValidation,
)
Validation(showValidationErrors, newIdValidation)
}
DialogProperty(
modifier = Modifier.padding(horizontal = 16.dp),
text = stringRes(R.string.ext__meta__label),
) {
FlorisOutlinedTextField(
JetPrefTextField(
modifier = Modifier.fillMaxWidth(),
value = newLabel,
onValueChange = { newLabel = it },
singleLine = true,
showValidationError = showValidationErrors,
validationResult = newLabelValidation,
)
Validation(showValidationErrors, newLabelValidation)
}
DialogProperty(
modifier = Modifier.padding(horizontal = 16.dp),
text = stringRes(R.string.ext__meta__authors),
) {
FlorisOutlinedTextField(
JetPrefTextField(
modifier = Modifier.fillMaxWidth(),
value = newAuthors,
onValueChange = { newAuthors = it },
showValidationError = showValidationErrors,
validationResult = newAuthorsValidation,
)
Validation(showValidationErrors, newAuthorsValidation)
}
}
}
@@ -860,7 +849,6 @@ private fun EditorSheetTextField(
showValidationError: Boolean = false,
validationResult: ValidationResult? = null,
) {
val borderColor = MaterialTheme.colorScheme.outline
Column(modifier = Modifier.padding(vertical = TextFieldVerticalPadding)) {
Row(
modifier = Modifier
@@ -880,18 +868,13 @@ private fun EditorSheetTextField(
)
}
}
FlorisOutlinedTextField(
JetPrefTextField(
modifier = modifier.fillMaxWidth(),
enabled = enabled,
value = value,
onValueChange = onValueChange,
singleLine = singleLine,
showValidationError = showValidationError,
validationResult = validationResult,
colors = OutlinedTextFieldDefaults.colors(
unfocusedBorderColor = borderColor,
disabledBorderColor = borderColor,
)
)
Validation(showValidationError, validationResult)
}
}

View File

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

View File

@@ -1,32 +1,33 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.ext
import androidx.compose.foundation.layout.Row
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.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.util.launchUrl
import dev.patrickgold.jetpref.datastore.ui.Preference
@Composable
@@ -40,36 +41,7 @@ fun ExtensionHomeScreen() = FlorisScreen {
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),
)
}
}
ImportExtensionBox(navController)
UpdateBox(extensionIndex = extensionIndex)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -152,8 +152,8 @@ fun HomeScreen() = FlorisScreen {
)
Preference(
icon = Icons.Outlined.Build,
title = stringRes(R.string.settings__advanced__title),
onClick = { navController.navigate(Routes.Settings.Advanced) },
title = stringRes(R.string.settings__other__title),
onClick = { navController.navigate(Routes.Settings.Other) },
)
Preference(
icon = Icons.Outlined.Info,

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,9 @@ 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.LibraryDefaults
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import com.mikepenz.aboutlibraries.ui.compose.m3.LibraryDefaults
import com.mikepenz.aboutlibraries.ui.compose.m3.libraryColors
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.florisScrollbar

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,58 +19,72 @@ 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.FormatColorFill
import androidx.compose.material.icons.filled.Language
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.Preview
import androidx.compose.material.icons.filled.SettingsBackupRestore
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
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 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
import dev.patrickgold.jetpref.datastore.ui.ColorPickerPreference
import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
import dev.patrickgold.jetpref.datastore.ui.isMaterialYou
import dev.patrickgold.jetpref.datastore.ui.listPrefEntries
import dev.patrickgold.jetpref.datastore.ui.vectorResource
import org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.color.ColorMappings
@Composable
fun AdvancedScreen() = FlorisScreen {
title = stringRes(R.string.settings__advanced__title)
fun OtherScreen() = FlorisScreen {
title = stringRes(R.string.settings__other__title)
previewFieldVisible = false
val navController = LocalNavController.current
val context = LocalContext.current
content {
ListPreference(
prefs.advanced.settingsTheme,
prefs.other.settingsTheme,
icon = Icons.Default.Palette,
title = stringRes(R.string.pref__advanced__settings_theme__label),
title = stringRes(R.string.pref__other__settings_theme__label),
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
},
ColorPickerPreference(
pref = prefs.other.accentColor,
title = stringRes(R.string.pref__other__settings_accent_color__label),
defaultValueLabel = stringRes(R.string.action__default),
icon = Icons.Default.FormatColorFill,
defaultColors = ColorMappings.colors,
showAlphaSlider = false,
enableAdvancedLayout = false,
colorOverride = {
if (it.isMaterialYou(context)) {
Color.Unspecified
} else {
it
}
}
)
ListPreference(
prefs.advanced.settingsLanguage,
prefs.other.settingsLanguage,
icon = Icons.Default.Language,
title = stringRes(R.string.pref__advanced__settings_language__label),
title = stringRes(R.string.pref__other__settings_language__label),
entries = listPrefEntries {
listOf(
"auto",
@@ -132,20 +146,19 @@ fun AdvancedScreen() = FlorisScreen {
}
)
SwitchPreference(
prefs.advanced.showAppIcon,
prefs.other.showAppIcon,
icon = Icons.Default.Preview,
title = stringRes(R.string.pref__advanced__show_app_icon__label),
title = stringRes(R.string.pref__other__show_app_icon__label),
summary = when {
AndroidVersion.ATLEAST_API29_Q -> stringRes(R.string.pref__advanced__show_app_icon__summary_atleast_q)
AndroidVersion.ATLEAST_API29_Q -> stringRes(R.string.pref__other__show_app_icon__summary_atleast_q)
else -> null
},
enabledIf = { AndroidVersion.ATMOST_API28_P },
)
ListPreference(
prefs.advanced.incognitoMode,
icon = vectorResource(id = R.drawable.ic_incognito),
title = stringRes(R.string.pref__advanced__incognito_mode__label),
entries = enumDisplayEntriesOf(IncognitoMode::class),
Preference(
icon = vectorResource(R.drawable.ic_keyboard_keys),
title = stringRes(R.string.physical_keyboard__title),
onClick = { navController.navigate(Routes.Settings.PhysicalKeyboard) },
)
Preference(
icon = Icons.Default.Adb,

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.app.settings.advanced
import android.content.Intent
import android.content.res.Configuration
import android.provider.Settings
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.Preference
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
@Composable
fun PhysicalKeyboardScreen() = FlorisScreen {
title = stringRes(R.string.physical_keyboard__title)
val context = LocalContext.current
val physicalKeyboardAttached by remember {
mutableStateOf(context.resources.configuration.keyboard != Configuration.KEYBOARD_NOKEYS)
}
val activityForResult = rememberLauncherForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { }
content {
if (physicalKeyboardAttached) {
Preference(
title = stringRes(R.string.physical_keyboard__system_settings__title),
summary = stringRes(R.string.physical_keyboard__system_settings__summary),
onClick = {
activityForResult.launch(Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS))
}
)
} else {
Preference(
title = stringRes(R.string.physical_keyboard__system_settings__title),
summary = stringRes(R.string.physical_keyboard__system_settings__summary_not_attached),
)
}
SwitchPreference(
pref = prefs.physicalKeyboard.showOnScreenKeyboard,
title = stringRes(R.string.physical_keyboard__show_on_screen_keyboard__title),
summary = stringRes(R.string.physical_keyboard__show_on_screen_keyboard__summary),
)
}
}

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package dev.patrickgold.florisboard.app.settings.clipboard
import androidx.compose.runtime.Composable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.clipboard.CLIPBOARD_HISTORY_NUM_GRID_COLUMNS_AUTO
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.pluralsRes
import dev.patrickgold.florisboard.lib.compose.stringRes
@@ -25,6 +26,7 @@ import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
import org.florisboard.lib.android.AndroidVersion
@OptIn(ExperimentalJetPrefDatastoreUi::class)
@Composable
@@ -51,12 +53,47 @@ fun ClipboardScreen() = FlorisScreen {
enabledIf = { prefs.clipboard.useInternalClipboard isEqualTo true },
)
PreferenceGroup(title = stringRes(R.string.pref__clipboard__group_clipboard_suggestion__label)) {
SwitchPreference(
prefs.clipboard.suggestionEnabled,
title = stringRes(R.string.pref__clipboard__suggestion_enabled__label),
summary = stringRes(R.string.pref__clipboard__suggestion_enabled__summary),
)
DialogSliderPreference(
prefs.clipboard.suggestionTimeout,
title = stringRes(R.string.pref__clipboard__suggestion_timeout__label),
valueLabel = { stringRes(R.string.pref__clipboard__suggestion_timeout__summary, "v" to it) },
min = 30,
max = 300,
stepIncrement = 5,
enabledIf = { prefs.clipboard.suggestionEnabled isEqualTo true },
)
}
PreferenceGroup(title = stringRes(R.string.pref__clipboard__group_clipboard_history__label)) {
SwitchPreference(
prefs.clipboard.historyEnabled,
title = stringRes(R.string.pref__clipboard__enable_clipboard_history__label),
summary = stringRes(R.string.pref__clipboard__enable_clipboard_history__summary),
)
DialogSliderPreference(
primaryPref = prefs.clipboard.numHistoryGridColumnsPortrait,
secondaryPref = prefs.clipboard.numHistoryGridColumnsLandscape,
title = stringRes(R.string.pref__clipboard__num_history_grid_columns__label),
primaryLabel = stringRes(R.string.screen_orientation__portrait),
secondaryLabel = stringRes(R.string.screen_orientation__landscape),
valueLabel = { numGridColumns ->
if (numGridColumns == CLIPBOARD_HISTORY_NUM_GRID_COLUMNS_AUTO) {
stringRes(R.string.general__auto)
} else {
numGridColumns.toString()
}
},
min = 0,
max = 10,
stepIncrement = 1,
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true },
)
SwitchPreference(
prefs.clipboard.cleanUpOld,
title = stringRes(R.string.pref__clipboard__clean_up_old__label),
@@ -71,6 +108,22 @@ fun ClipboardScreen() = FlorisScreen {
stepIncrement = 5,
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true && prefs.clipboard.cleanUpOld isEqualTo true },
)
SwitchPreference(
prefs.clipboard.autoCleanSensitive,
title = stringRes(R.string.pref__clipboard__auto_clean_sensitive__label),
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true },
visibleIf = { AndroidVersion.ATLEAST_API33_T },
)
DialogSliderPreference(
prefs.clipboard.autoCleanSensitiveAfter,
title = stringRes(R.string.pref__clipboard__auto_clean_sensitive_after__label),
valueLabel = { pluralsRes(R.plurals.unit__seconds__written, it, "v" to it) },
min = 0,
max = 300,
stepIncrement = 10,
enabledIf = { prefs.clipboard.historyEnabled isEqualTo true && prefs.clipboard.autoCleanSensitive isEqualTo true },
visibleIf = { AndroidVersion.ATLEAST_API33_T },
)
SwitchPreference(
prefs.clipboard.limitHistorySize,
title = stringRes(R.string.pref__clipboard__limit_history_size__label),

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,14 +56,15 @@ 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.compose.FlorisIconButton
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedTextField
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.Validation
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 dev.patrickgold.jetpref.material.ui.JetPrefTextField
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.florisboard.lib.android.showLongToast
@@ -366,39 +367,35 @@ fun UserDictionaryScreen(type: UserDictionaryType) = FlorisScreen {
) {
Column {
DialogProperty(text = stringRes(R.string.settings__udm__dialog__word_label)) {
FlorisOutlinedTextField(
JetPrefTextField(
value = word,
onValueChange = { word = it },
showValidationError = showValidationErrors,
validationResult = wordValidation,
)
Validation(showValidationErrors, wordValidation)
}
DialogProperty(text = stringRes(
R.string.settings__udm__dialog__freq_label,
"f_min" to FREQUENCY_MIN, "f_max" to FREQUENCY_MAX,
)) {
FlorisOutlinedTextField(
JetPrefTextField(
value = freq,
onValueChange = { freq = it },
showValidationError = showValidationErrors,
validationResult = freqValidation,
)
Validation(showValidationErrors, freqValidation)
}
DialogProperty(text = stringRes(R.string.settings__udm__dialog__shortcut_label)) {
FlorisOutlinedTextField(
JetPrefTextField(
value = shortcut,
onValueChange = { shortcut = it },
showValidationError = showValidationErrors,
validationResult = shortcutValidation,
)
Validation(showValidationErrors, shortcutValidation)
}
DialogProperty(text = stringRes(R.string.settings__udm__dialog__locale_label)) {
FlorisOutlinedTextField(
JetPrefTextField(
value = locale,
onValueChange = { locale = it },
showValidationError = showValidationErrors,
validationResult = localeValidation,
)
Validation(showValidationErrors, localeValidation)
}
}
}

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,11 +20,8 @@ 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 org.florisboard.lib.android.AndroidVersion
import org.florisboard.lib.android.systemVibratorOrNull
import org.florisboard.lib.android.vibrate
import dev.patrickgold.florisboard.ime.input.InputFeedbackActivationMode
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
import dev.patrickgold.florisboard.lib.compose.stringRes
import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
@@ -32,6 +29,8 @@ import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
import dev.patrickgold.jetpref.datastore.ui.ListPreference
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
import org.florisboard.lib.android.systemVibratorOrNull
import org.florisboard.lib.android.vibrate
@OptIn(ExperimentalJetPrefDatastoreUi::class)
@Composable
@@ -138,8 +137,6 @@ fun InputFeedbackScreen() = FlorisScreen {
summary = { strength ->
if (vibrator == null || !vibrator.hasVibrator()) {
stringRes(R.string.pref__input_feedback__haptic_vibration_strength__summary_no_vibrator)
} else if (AndroidVersion.ATMOST_API25_N_MR1) {
stringRes(R.string.pref__input_feedback__haptic_vibration_strength__summary_unsupported_android_version)
} else if (!vibrator.hasAmplitudeControl()) {
stringRes(R.string.pref__input_feedback__haptic_vibration_strength__summary_no_amplitude_ctrl)
} else {
@@ -157,7 +154,7 @@ fun InputFeedbackScreen() = FlorisScreen {
prefs.inputFeedback.hapticEnabled isEqualTo true &&
prefs.inputFeedback.hapticVibrationMode isEqualTo HapticVibrationMode.USE_VIBRATOR_DIRECTLY &&
vibrator != null && vibrator.hasVibrator() &&
AndroidVersion.ATLEAST_API26_O && vibrator.hasAmplitudeControl()
vibrator.hasAmplitudeControl()
},
)
SwitchPreference(

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -107,8 +107,10 @@ fun KeyboardScreen() = FlorisScreen {
PreferenceGroup(title = stringRes(R.string.pref__keyboard__group_layout__label)) {
ListPreference(
prefs.keyboard.oneHandedMode,
prefs.keyboard.oneHandedModeEnabled,
title = stringRes(R.string.pref__keyboard__one_handed_mode__label),
entries = enumDisplayEntriesOf(OneHandedMode::class),
summarySwitchDisabled = stringRes(R.string.state__disabled),
)
DialogSliderPreference(
prefs.keyboard.oneHandedModeScaleFactor,
@@ -117,7 +119,7 @@ fun KeyboardScreen() = FlorisScreen {
min = 70,
max = 90,
stepIncrement = 1,
enabledIf = { prefs.keyboard.oneHandedMode isNotEqualTo OneHandedMode.OFF },
enabledIf = { prefs.keyboard.oneHandedModeEnabled.isTrue() },
)
ListPreference(
prefs.keyboard.landscapeInputUiMode,

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 Patrick Goldinger
* Copyright (C) 2021-2025 The FlorisBoard Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,6 +53,7 @@ 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
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@@ -103,6 +104,10 @@ fun LocalizationScreen() = FlorisScreen {
title = stringRes(R.string.settings__localization__display_language_names_in__label),
entries = enumDisplayEntriesOf(DisplayLanguageNamesIn::class),
)
SwitchPreference(
prefs.localization.displayKeyboardLabelsInSubtypeLanguage,
title = stringRes(R.string.settings__localization__display_keyboard_labels_in_subtype_language),
)
Preference(
title = stringRes(R.string.settings__localization__language_pack_title),
summary = stringRes(R.string.settings__localization__language_pack_summary),

View File

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

View File

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

View File

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

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