Compare commits
124 Commits
v0.4.6
...
v0.5.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a365e76383 | ||
|
|
7c4747d451 | ||
|
|
12be43e100 | ||
|
|
207cf244e6 | ||
|
|
6f45cf8456 | ||
|
|
5b73de5700 | ||
|
|
25c94e8270 | ||
|
|
0cd703427a | ||
|
|
3871978abc | ||
|
|
a9502be471 | ||
|
|
a5f2844488 | ||
|
|
dd67497154 | ||
|
|
01c7512c01 | ||
|
|
fe37ea914c | ||
|
|
fa768c0e2a | ||
|
|
bcd3d1719b | ||
|
|
55f881d8a0 | ||
|
|
cd817dec93 | ||
|
|
cdf8bc2825 | ||
|
|
62d07b0142 | ||
|
|
f50cd2de58 | ||
|
|
396a47cde9 | ||
|
|
51e67c7293 | ||
|
|
0bc64c6253 | ||
|
|
f571013fe5 | ||
|
|
5f7ca53458 | ||
|
|
0cacb9a671 | ||
|
|
30d36b7541 | ||
|
|
3ece15f516 | ||
|
|
603fab1831 | ||
|
|
90838012ad | ||
|
|
e366c94d55 | ||
|
|
a0ffa3feb1 | ||
|
|
ecbf5c4e66 | ||
|
|
023645646c | ||
|
|
553251d3c1 | ||
|
|
92ce04d5d9 | ||
|
|
9930eb1bca | ||
|
|
47b2d81f72 | ||
|
|
e6d6260d72 | ||
|
|
dd02948a00 | ||
|
|
4a12b3ded0 | ||
|
|
6acfa7f349 | ||
|
|
d3e2dda165 | ||
|
|
a5ec6a10b3 | ||
|
|
0a8260b7fa | ||
|
|
4cddc9b305 | ||
|
|
b4835b869a | ||
|
|
11c6dc8a0d | ||
|
|
71a2baf402 | ||
|
|
94bfd39a9b | ||
|
|
d473343ca3 | ||
|
|
5101db7169 | ||
|
|
08e10639d1 | ||
|
|
741dd82003 | ||
|
|
4c2bfc5dab | ||
|
|
ce3cb4427a | ||
|
|
463e3a3588 | ||
|
|
da611d3077 | ||
|
|
d0afe023a6 | ||
|
|
00f01b59db | ||
|
|
7a1cc211f3 | ||
|
|
1e29204d9c | ||
|
|
d541eed655 | ||
|
|
aaf7e62ed9 | ||
|
|
29cbc4f373 | ||
|
|
791f3d2a69 | ||
|
|
6595aa4d1a | ||
|
|
815ea0845a | ||
|
|
37c5256769 | ||
|
|
b85703db36 | ||
|
|
bc1bc8fece | ||
|
|
b3c6589326 | ||
|
|
8f44d04a6f | ||
|
|
349758991a | ||
|
|
fed979dec9 | ||
|
|
d6f8555bdf | ||
|
|
5afd6bd722 | ||
|
|
0716420697 | ||
|
|
b923a5bf65 | ||
|
|
3c2b2ae473 | ||
|
|
1e1881e6ea | ||
|
|
3acda3745a | ||
|
|
2a8c67c4f4 | ||
|
|
0d572fc1ae | ||
|
|
7810d8034c | ||
|
|
6b9fc555f0 | ||
|
|
f352c768f4 | ||
|
|
24d6667b52 | ||
|
|
d29cfff7d4 | ||
|
|
babf58bf53 | ||
|
|
701088c842 | ||
|
|
4fdbb7c235 | ||
|
|
5831bd84ad | ||
|
|
dd97ff09b6 | ||
|
|
a5407502f3 | ||
|
|
def05ef3a7 | ||
|
|
8ec03c09cc | ||
|
|
a298687f6e | ||
|
|
2488614d22 | ||
|
|
ca8ca65533 | ||
|
|
8e134cc15f | ||
|
|
17860815b6 | ||
|
|
bb502b5f8c | ||
|
|
0e51f25bb0 | ||
|
|
c1e50c9684 | ||
|
|
c377cd9ed7 | ||
|
|
1fc3b536d9 | ||
|
|
ae645fa327 | ||
|
|
bfd20055fc | ||
|
|
15aa6a6bb3 | ||
|
|
e4ef14e684 | ||
|
|
39d7ea4fc0 | ||
|
|
6d330f807a | ||
|
|
e6bc0657f6 | ||
|
|
4686234ba2 | ||
|
|
57e4765ce7 | ||
|
|
aaf26a7a4b | ||
|
|
f8f6756b84 | ||
|
|
35fd70ce6d | ||
|
|
a0ebd62f9a | ||
|
|
3dacd3c2d0 | ||
|
|
c73b8dda0b | ||
|
|
5353a01226 |
@@ -23,7 +23,6 @@ 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)
|
||||
}
|
||||
|
||||
@@ -52,6 +51,7 @@ android {
|
||||
freeCompilerArgs = listOf(
|
||||
"-opt-in=kotlin.contracts.ExperimentalContracts",
|
||||
"-Xjvm-default=all-compatibility",
|
||||
"-Xwhen-guards",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -207,12 +207,6 @@ dependencies {
|
||||
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)
|
||||
|
||||
androidTestImplementation(libs.androidx.test.ext)
|
||||
androidTestImplementation(libs.androidx.test.espresso.core)
|
||||
}
|
||||
|
||||
@@ -114,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 -->
|
||||
|
||||
@@ -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"}
|
||||
}
|
||||
}
|
||||
@@ -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"}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
@@ -8,7 +9,20 @@
|
||||
"--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",
|
||||
|
||||
@@ -16,8 +30,10 @@
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
"window": {
|
||||
"background": "var(--background)",
|
||||
"foreground": "var(--on-background)",
|
||||
"clip": "no"
|
||||
},
|
||||
|
||||
"key": {
|
||||
@@ -25,48 +41,69 @@
|
||||
"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"
|
||||
},
|
||||
@@ -78,117 +115,180 @@
|
||||
"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)"
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape)",
|
||||
"text-max-lines": "2",
|
||||
"text-align": "center",
|
||||
"text-overflow": "ellipsis"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
"foreground": "var(--on-background-disabled)"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "circle()"
|
||||
},
|
||||
|
||||
"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-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-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"
|
||||
},
|
||||
"clipboard-content": {
|
||||
"padding": "10dp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"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-action": {
|
||||
"font-size": "16sp",
|
||||
"padding": "12dp"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"clipboard-clear-all-dialog": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "1dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
"clipboard-clear-all-dialog-message": {
|
||||
"padding": "16dp"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
"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 +313,65 @@
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#00000011"
|
||||
"foreground": "var(--incognito-icon-color)"
|
||||
},
|
||||
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
@@ -8,7 +9,20 @@
|
||||
"--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",
|
||||
|
||||
@@ -16,56 +30,82 @@
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
"window": {
|
||||
"background": "var(--background)",
|
||||
"foreground": "var(--on-background)",
|
||||
"clip": "no"
|
||||
},
|
||||
|
||||
"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"
|
||||
},
|
||||
@@ -77,7 +117,6 @@
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-key:pressed": {
|
||||
@@ -85,48 +124,80 @@
|
||||
"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)"
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape)",
|
||||
"text-max-lines": "2",
|
||||
"text-align": "center",
|
||||
"text-overflow": "ellipsis"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
"foreground": "var(--on-background-disabled)"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "circle()"
|
||||
},
|
||||
"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)",
|
||||
@@ -136,7 +207,11 @@
|
||||
"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)",
|
||||
@@ -151,43 +226,80 @@
|
||||
"foreground": "var(--on-surface)",
|
||||
"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"
|
||||
},
|
||||
"clipboard-content": {
|
||||
"padding": "10dp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
"clipboard-item-popup-action": {
|
||||
"font-size": "16sp",
|
||||
"padding": "12dp"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"clipboard-clear-all-dialog": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "1dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
"clipboard-clear-all-dialog-message": {
|
||||
"padding": "16dp"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
"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 +324,66 @@
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#00000011"
|
||||
"foreground": "var(--incognito-icon-color)"
|
||||
},
|
||||
|
||||
"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"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
@@ -7,8 +8,16 @@
|
||||
"--background": "#212121",
|
||||
"--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",
|
||||
|
||||
@@ -16,8 +25,10 @@
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
"window": {
|
||||
"background": "var(--background)",
|
||||
"foreground": "var(--on-background)",
|
||||
"clip": "no"
|
||||
},
|
||||
|
||||
"key": {
|
||||
@@ -25,48 +36,68 @@
|
||||
"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"
|
||||
},
|
||||
@@ -78,117 +109,180 @@
|
||||
"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)"
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape)",
|
||||
"text-max-lines": "2",
|
||||
"text-align": "center",
|
||||
"text-overflow": "ellipsis"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
"foreground": "var(--on-background-disabled)"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "circle()"
|
||||
},
|
||||
|
||||
"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-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-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"
|
||||
},
|
||||
"clipboard-content": {
|
||||
"padding": "10dp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"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-action": {
|
||||
"font-size": "16sp",
|
||||
"padding": "12dp"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"clipboard-clear-all-dialog": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "1dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
"clipboard-clear-all-dialog-message": {
|
||||
"padding": "16dp"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
"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 +307,63 @@
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#ffffff11"
|
||||
"foreground": "var(--incognito-icon-color)"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
@@ -7,8 +8,16 @@
|
||||
"--background": "#212121",
|
||||
"--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",
|
||||
|
||||
@@ -16,56 +25,81 @@
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
"window": {
|
||||
"background": "var(--background)",
|
||||
"foreground": "var(--on-background)",
|
||||
"clip": "no"
|
||||
},
|
||||
|
||||
"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"
|
||||
},
|
||||
@@ -77,7 +111,6 @@
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-key:pressed": {
|
||||
@@ -85,48 +118,80 @@
|
||||
"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)"
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape)",
|
||||
"text-max-lines": "2",
|
||||
"text-align": "center",
|
||||
"text-overflow": "ellipsis"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
"foreground": "var(--on-background-disabled)"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "circle()"
|
||||
},
|
||||
"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)",
|
||||
@@ -136,7 +201,11 @@
|
||||
"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)",
|
||||
@@ -151,43 +220,80 @@
|
||||
"foreground": "var(--on-surface)",
|
||||
"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"
|
||||
},
|
||||
"clipboard-content": {
|
||||
"padding": "10dp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
"clipboard-item-popup-action": {
|
||||
"font-size": "16sp",
|
||||
"padding": "12dp"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"clipboard-clear-all-dialog": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "1dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
"clipboard-clear-all-dialog-message": {
|
||||
"padding": "16dp"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
"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 +318,63 @@
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#ffffff11"
|
||||
"foreground": "var(--incognito-icon-color)"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
|
||||
"@defines": {
|
||||
"--primary": "#388e3c",
|
||||
"--primary-variant": "#306d32",
|
||||
@@ -7,7 +8,15 @@
|
||||
"--background": "#000000",
|
||||
"--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",
|
||||
@@ -16,8 +25,10 @@
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
"window": {
|
||||
"background": "var(--background)",
|
||||
"foreground": "var(--on-background)",
|
||||
"clip": "no"
|
||||
},
|
||||
|
||||
"key": {
|
||||
@@ -25,48 +36,68 @@
|
||||
"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"
|
||||
},
|
||||
@@ -78,7 +109,6 @@
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-key:pressed": {
|
||||
@@ -86,109 +116,177 @@
|
||||
"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)"
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape)",
|
||||
"text-max-lines": "2",
|
||||
"text-align": "center",
|
||||
"text-overflow": "ellipsis"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
"foreground": "var(--on-background-disabled)"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "circle()"
|
||||
},
|
||||
|
||||
"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-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-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"
|
||||
},
|
||||
"clipboard-content": {
|
||||
"padding": "10dp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"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-action": {
|
||||
"font-size": "16sp",
|
||||
"padding": "12dp"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"clipboard-clear-all-dialog": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "1dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
"clipboard-clear-all-dialog-message": {
|
||||
"padding": "16dp"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
"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 +297,77 @@
|
||||
"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)"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://schemas.florisboard.org/snygg/v2/stylesheet",
|
||||
"@defines": {
|
||||
"--primary": "#388e3c",
|
||||
"--primary-variant": "#306d32",
|
||||
@@ -7,7 +8,15 @@
|
||||
"--background": "#000000",
|
||||
"--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",
|
||||
@@ -16,56 +25,81 @@
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
"window": {
|
||||
"background": "var(--background)",
|
||||
"foreground": "var(--on-background)",
|
||||
"clip": "no"
|
||||
},
|
||||
|
||||
"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"
|
||||
},
|
||||
@@ -77,7 +111,6 @@
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-key:pressed": {
|
||||
@@ -85,48 +118,80 @@
|
||||
"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)"
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape)",
|
||||
"text-max-lines": "2",
|
||||
"text-align": "center",
|
||||
"text-overflow": "ellipsis"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
"foreground": "var(--on-background-disabled)"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "circle()"
|
||||
},
|
||||
"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)",
|
||||
@@ -136,7 +201,11 @@
|
||||
"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)",
|
||||
@@ -151,43 +220,80 @@
|
||||
"foreground": "var(--on-surface)",
|
||||
"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"
|
||||
},
|
||||
"clipboard-content": {
|
||||
"padding": "10dp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"margin": "4dp",
|
||||
"padding": "12dp 8dp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
"clipboard-item-popup-action": {
|
||||
"font-size": "16sp",
|
||||
"padding": "12dp"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"clipboard-clear-all-dialog": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "1dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
"clipboard-clear-all-dialog-message": {
|
||||
"padding": "16dp"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
"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 +304,77 @@
|
||||
"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)"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,10 +49,9 @@ 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
|
||||
@@ -103,7 +102,6 @@ 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.ime.theme.WallpaperChangeReceiver
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButton
|
||||
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.lib.compose.SystemUiIme
|
||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||
@@ -115,6 +113,7 @@ 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
|
||||
@@ -122,14 +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 org.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import org.florisboard.lib.snygg.ui.shape
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.snyggBorder
|
||||
import org.florisboard.lib.snygg.ui.snyggShadow
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import java.lang.ref.WeakReference
|
||||
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
|
||||
@@ -283,7 +279,16 @@ 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)
|
||||
}
|
||||
@Suppress("DEPRECATION") // We do not retrieve the wallpaper but only listen to changes
|
||||
@@ -457,6 +462,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,
|
||||
@@ -519,6 +528,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
*/
|
||||
private fun updateSoftInputWindowLayoutParameters() {
|
||||
val w = window?.window ?: return
|
||||
// TODO: setting this to false kinda helps with the nav bar color bug, but introduces padding issues...
|
||||
WindowCompat.setDecorFitsSystemWindows(w, true)
|
||||
ViewUtils.updateLayoutHeightOf(w, WindowManager.LayoutParams.MATCH_PARENT)
|
||||
val layoutHeight = if (isFullscreenUiMode) {
|
||||
@@ -556,19 +566,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),
|
||||
) {
|
||||
DevtoolsOverlay(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
)
|
||||
}
|
||||
ImeUi()
|
||||
SystemUiIme()
|
||||
}
|
||||
SystemUiIme()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -579,25 +588,22 @@ 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 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 = mapOf(FlorisImeUi.Attr.ShiftState to state.inputShiftState.attrName()),
|
||||
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,
|
||||
) {
|
||||
val configuration = LocalConfiguration.current
|
||||
val bottomOffset by if (configuration.isOrientationPortrait()) {
|
||||
@@ -609,18 +615,18 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
// Apply system bars padding here (we already drew our keyboard background)
|
||||
.safeDrawingPadding()
|
||||
// FIXME: removing this fixes the Smartbar sizing but breaks one-handed-mode
|
||||
//.height(IntrinsicSize.Min)
|
||||
.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,
|
||||
@@ -639,7 +645,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oneHandedMode == OneHandedMode.START && configuration.isOrientationPortrait()) {
|
||||
if (oneHandedModeEnabled && oneHandedMode == OneHandedMode.START && configuration.isOrientationPortrait()) {
|
||||
OneHandedPanel(
|
||||
panelSide = OneHandedMode.END,
|
||||
weight = 1f - keyboardWeight,
|
||||
@@ -740,45 +746,38 @@ 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(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)
|
||||
@@ -787,21 +786,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",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ 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.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
@@ -41,11 +41,15 @@ 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 dev.patrickgold.florisboard.lib.compose.ColorPreferenceSerializer
|
||||
@@ -55,51 +59,16 @@ import dev.patrickgold.florisboard.lib.util.VersionName
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
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
|
||||
import org.florisboard.lib.snygg.SnyggLevel
|
||||
|
||||
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 accentColor = custom(
|
||||
key = "advanced__accent_color",
|
||||
default = when (AndroidVersion.ATLEAST_API31_S) {
|
||||
true -> Color.Unspecified
|
||||
false -> DEFAULT_GREEN
|
||||
},
|
||||
serializer = ColorPreferenceSerializer,
|
||||
)
|
||||
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(
|
||||
@@ -146,6 +115,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()
|
||||
@@ -506,7 +483,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",
|
||||
@@ -578,14 +559,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
|
||||
@@ -600,6 +581,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,
|
||||
@@ -610,6 +595,30 @@ 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 smartbar = Smartbar()
|
||||
inner class Smartbar {
|
||||
val enabled = boolean(
|
||||
@@ -686,13 +695,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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -728,9 +738,9 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
// key = "theme__sunset_time",
|
||||
// default = LocalTime.of(18, 0),
|
||||
//)
|
||||
val editorDisplayColorsAs = enum(
|
||||
key = "theme__editor_display_colors_as",
|
||||
default = DisplayColorsAs.HEX8,
|
||||
val editorColorRepresentation = enum(
|
||||
key = "theme__editor_color_representation",
|
||||
default = ColorRepresentation.HEX,
|
||||
)
|
||||
val editorDisplayKbdAfterDialogs = enum(
|
||||
key = "theme__editor_display_kbd_after_dialogs",
|
||||
@@ -744,34 +754,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
|
||||
@@ -786,19 +768,75 @@ 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") {
|
||||
val prefs by florisPreferenceModel()
|
||||
prefs.keyboard.oneHandedModeEnabled.set(true)
|
||||
entry.keepAsIs()
|
||||
} else {
|
||||
entry.reset()
|
||||
}
|
||||
}
|
||||
"smartbar__action_arrangement" -> {
|
||||
val arrangement = QuickActionJsonConfig.decodeFromString<QuickActionArrangement>(entry.rawValue)
|
||||
val newArrangement = arrangement.copy(
|
||||
dynamicActions = arrangement.dynamicActions.map { action ->
|
||||
if (action is QuickAction.InsertKey && action.data.code == KeyCode.COMPACT_LAYOUT_TO_RIGHT) {
|
||||
action.copy(TextKeyData.TOGGLE_COMPACT_LAYOUT)
|
||||
} else {
|
||||
action
|
||||
}
|
||||
}
|
||||
)
|
||||
val json = QuickActionJsonConfig.encodeToString(newArrangement)
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ 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
|
||||
@@ -41,9 +41,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
|
||||
|
||||
@@ -58,19 +58,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),
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -102,18 +102,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,
|
||||
)
|
||||
}
|
||||
@@ -376,10 +382,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),
|
||||
|
||||
@@ -36,7 +36,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.isUnspecified
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
@@ -89,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
|
||||
}
|
||||
}
|
||||
@@ -118,8 +117,7 @@ class FlorisAppActivity : ComponentActivity() {
|
||||
AppVersionUtils.updateVersionOnInstallAndLastUse(this, prefs)
|
||||
setContent {
|
||||
ProvideLocalizedResources(resourcesContext) {
|
||||
val accentColor by prefs.advanced.accentColor.observeAsState()
|
||||
FlorisAppTheme(theme = appTheme, isMaterialYouAware = accentColor.isUnspecified) {
|
||||
FlorisAppTheme(theme = appTheme) {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
AppContent()
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ 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.OtherScreen
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.BackupScreen
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.RestoreScreen
|
||||
import dev.patrickgold.florisboard.app.settings.clipboard.ClipboardScreen
|
||||
@@ -110,9 +110,9 @@ 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 Backup = "settings/other/backup"
|
||||
const val Restore = "settings/other/restore"
|
||||
|
||||
const val About = "settings/about"
|
||||
const val ProjectLicense = "settings/about/project-license"
|
||||
@@ -239,7 +239,7 @@ object Routes {
|
||||
|
||||
composableWithDeepLink(Settings.Media) { MediaScreen() }
|
||||
|
||||
composableWithDeepLink(Settings.Advanced) { AdvancedScreen() }
|
||||
composableWithDeepLink(Settings.Other) { OtherScreen() }
|
||||
composableWithDeepLink(Settings.Backup) { BackupScreen() }
|
||||
composableWithDeepLink(Settings.Restore) { RestoreScreen() }
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ import android.content.Context
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -79,59 +77,38 @@ private val LightColorPalette = lightColorScheme(
|
||||
@Composable
|
||||
fun getColorScheme(
|
||||
context: Context,
|
||||
isMaterialYouAware: Boolean,
|
||||
themeColor: Color,
|
||||
theme: AppTheme,
|
||||
): ColorScheme {
|
||||
val prefs by florisPreferenceModel()
|
||||
val accentColor by prefs.other.accentColor.observeAsState()
|
||||
val isDark = isSystemInDarkTheme()
|
||||
|
||||
return when (theme) {
|
||||
|
||||
AppTheme.AUTO -> {
|
||||
if (isMaterialYouAware && AndroidVersion.ATLEAST_API31_S) {
|
||||
when {
|
||||
isDark -> dynamicDarkColorScheme(context)
|
||||
else -> dynamicLightColorScheme(context)
|
||||
}
|
||||
if (isDark) {
|
||||
ColorMappings.dynamicDarkColorScheme(context, accentColor)
|
||||
} else {
|
||||
ColorMappings.getColorSchemeOrDefault(themeColor, isDark, true)
|
||||
ColorMappings.dynamicLightColorScheme(context, accentColor)
|
||||
}
|
||||
}
|
||||
|
||||
AppTheme.DARK -> {
|
||||
if (isMaterialYouAware && AndroidVersion.ATLEAST_API31_S) {
|
||||
dynamicDarkColorScheme(context)
|
||||
} else {
|
||||
ColorMappings.getColorSchemeOrDefault(themeColor, isDark = true, settings = true)
|
||||
}
|
||||
ColorMappings.dynamicDarkColorScheme(context, accentColor)
|
||||
}
|
||||
|
||||
AppTheme.LIGHT -> {
|
||||
if (isMaterialYouAware && AndroidVersion.ATLEAST_API31_S) {
|
||||
dynamicLightColorScheme(context)
|
||||
} else {
|
||||
ColorMappings.getColorSchemeOrDefault(themeColor, isDark = false, settings = true)
|
||||
}
|
||||
ColorMappings.dynamicLightColorScheme(context, accentColor)
|
||||
}
|
||||
|
||||
AppTheme.AMOLED_DARK -> {
|
||||
if (isMaterialYouAware && AndroidVersion.ATLEAST_API31_S) {
|
||||
dynamicDarkColorScheme(context).amoled()
|
||||
} else {
|
||||
ColorMappings.getColorSchemeOrDefault(themeColor, isDark = true, settings = true).amoled()
|
||||
}
|
||||
ColorMappings.dynamicDarkColorScheme(context, accentColor).amoled()
|
||||
}
|
||||
|
||||
AppTheme.AUTO_AMOLED -> {
|
||||
if (isMaterialYouAware && AndroidVersion.ATLEAST_API31_S) {
|
||||
when {
|
||||
isDark -> dynamicDarkColorScheme(context).amoled()
|
||||
else -> dynamicLightColorScheme(context)
|
||||
}
|
||||
if (isDark) {
|
||||
ColorMappings.dynamicDarkColorScheme(context, accentColor).amoled()
|
||||
} else {
|
||||
with(ColorMappings.getColorSchemeOrDefault(themeColor, isDark, true)) {
|
||||
if (isDark) amoled() else this
|
||||
}
|
||||
ColorMappings.dynamicLightColorScheme(context, accentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,17 +121,11 @@ fun ColorScheme.amoled(): ColorScheme {
|
||||
@Composable
|
||||
fun FlorisAppTheme(
|
||||
theme: AppTheme,
|
||||
isMaterialYouAware: Boolean,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val accent by prefs.advanced.accentColor.observeAsState()
|
||||
|
||||
val colors = getColorScheme(
|
||||
context = LocalContext.current,
|
||||
theme = theme,
|
||||
isMaterialYouAware = isMaterialYouAware,
|
||||
themeColor = accent,
|
||||
)
|
||||
|
||||
val darkTheme =
|
||||
|
||||
@@ -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
|
||||
@@ -45,12 +46,15 @@ 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.*
|
||||
|
||||
@@ -62,6 +66,7 @@ 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()
|
||||
@@ -70,6 +75,7 @@ fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
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,
|
||||
@@ -91,6 +97,10 @@ fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
if (devtoolsEnabled && showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
|
||||
DevtoolsInlineAutofillOverlay()
|
||||
}
|
||||
val loadFailure = themeInfo?.loadFailure
|
||||
if (loadFailure != null) {
|
||||
DevtoolsStylesheetFailedToLoadOverlay(loadFailure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,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 you’re trying to load a theme designed for FlorisBoard v0.4 (Snygg v1), which isn’t compatible with the latest release using Snygg v2.
|
||||
|
||||
If you are the theme author, please update your theme to support Snygg v2.
|
||||
|
||||
If you’re a user, please update your theme via the Addons Store. If an updated version isn’t available yet, please select one of the built-in themes during this transition period.
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsOverlayBox(
|
||||
title: String,
|
||||
|
||||
@@ -21,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
|
||||
@@ -29,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
|
||||
@@ -41,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
|
||||
|
||||
@@ -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()}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 androidx.core.content.MimeTypeFilter
|
||||
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
|
||||
|
||||
const val FONTS = "fonts"
|
||||
const val IMAGES = "images"
|
||||
|
||||
val MIME_TYPES = mapOf(
|
||||
FONTS to listOf(
|
||||
// Source: https://www.alienfactory.co.uk/articles/mime-types-for-web-fonts-in-bedsheet#mimeTypes
|
||||
"font/*",
|
||||
"application/vnd.ms-fontobject", // .eot
|
||||
"application/font-woff", // .woff
|
||||
"application/x-font-truetype", // .ttf
|
||||
"application/x-font-opentype", // .otf
|
||||
),
|
||||
IMAGES to listOf(
|
||||
"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 types = MIME_TYPES[currentImportDest!!]!!
|
||||
checkNotNull(MimeTypeFilter.matches(mimeType, types.toTypedArray())) {
|
||||
"Given file mime type was '$mimeType', expected one of $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 = "Rename or remove",
|
||||
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 remove")
|
||||
}
|
||||
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(
|
||||
value = fileNameInput,
|
||||
onValueChange = { fileNameInput = it },
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileList(
|
||||
title = FONTS.replaceFirstChar { it.uppercase() },
|
||||
icon = Icons.Default.TextFields,
|
||||
files = fontFiles,
|
||||
) {
|
||||
currentImportDest = FONTS
|
||||
importLauncher.launch("*/*")
|
||||
}
|
||||
|
||||
FileList(
|
||||
title = IMAGES.replaceFirstChar { it.uppercase() },
|
||||
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 = "Import ${dest.substring(0, dest.length - 1)}",
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,33 +16,18 @@
|
||||
|
||||
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
|
||||
@@ -56,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)
|
||||
|
||||
|
||||
@@ -113,6 +113,9 @@ fun ExtensionListScreen(type: ExtensionListScreenType, showUpdate: Boolean) = Fl
|
||||
contentPadding = PaddingValues(bottom = fabHeightDp),
|
||||
) {
|
||||
if (showUpdate) {
|
||||
item {
|
||||
ImportExtensionBox(navController)
|
||||
}
|
||||
item {
|
||||
UpdateBox(extensionIndex = extensionIndex)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package dev.patrickgold.florisboard.app.settings
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.Assignment
|
||||
import androidx.compose.material.icons.filled.Adb
|
||||
import androidx.compose.material.icons.filled.Extension
|
||||
import androidx.compose.material.icons.filled.Gesture
|
||||
import androidx.compose.material.icons.filled.Language
|
||||
@@ -152,8 +153,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,
|
||||
|
||||
@@ -34,7 +34,6 @@ import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
@@ -46,14 +45,13 @@ 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
|
||||
@@ -61,14 +59,14 @@ fun AdvancedScreen() = FlorisScreen {
|
||||
|
||||
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),
|
||||
)
|
||||
ColorPickerPreference(
|
||||
pref = prefs.advanced.accentColor,
|
||||
title = stringRes(R.string.pref__advanced__settings_accent_color__label),
|
||||
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,
|
||||
@@ -83,9 +81,9 @@ fun AdvancedScreen() = FlorisScreen {
|
||||
}
|
||||
)
|
||||
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",
|
||||
@@ -147,21 +145,15 @@ 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 = Icons.Default.Adb,
|
||||
title = stringRes(R.string.devtools__title),
|
||||
@@ -52,6 +52,23 @@ 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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,8 +48,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@@ -59,7 +59,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
@@ -82,30 +81,33 @@ import dev.patrickgold.florisboard.ime.keyboard.computeImageVector
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeLabel
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUiSpec
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.NATIVE_NULLPTR
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.stringRes
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisChip
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisDropdownMenu
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisHyperlinkText
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import org.florisboard.lib.snygg.SnyggLevel
|
||||
import org.florisboard.lib.snygg.SnyggRule
|
||||
import dev.patrickgold.florisboard.lib.util.InputMethodUtils
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefDropdown
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefTextField
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefTextFieldDefaults
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.stringRes
|
||||
import org.florisboard.lib.kotlin.curlyFormat
|
||||
import org.florisboard.lib.kotlin.getKeyByValue
|
||||
import org.florisboard.lib.snygg.SnyggAnnotationRule
|
||||
import org.florisboard.lib.snygg.SnyggElementRule
|
||||
import org.florisboard.lib.snygg.SnyggRule
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.NonNullSaver
|
||||
|
||||
private val TransparentTextSelectionColors = TextSelectionColors(
|
||||
handleColor = Color.Transparent,
|
||||
backgroundColor = Color.Transparent,
|
||||
)
|
||||
internal val SnyggEmptyRuleForAdding = SnyggRule(element = "- select -")
|
||||
internal val SnyggEmptyRuleForAdding = SnyggElementRule(elementName = "--select--")
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
@@ -116,69 +118,69 @@ internal fun EditRuleDialog(
|
||||
onDeleteRule: (rule: SnyggRule) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val isAddRuleDialog = initRule == SnyggEmptyRuleForAdding
|
||||
var showSelectAsError by rememberSaveable { mutableStateOf(false) }
|
||||
var showAlreadyExistsError by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val possibleElementNames = remember {
|
||||
listOf(SnyggEmptyRuleForAdding.element) + FlorisImeUiSpec.elements.keys
|
||||
val possibleRuleTemplates = remember {
|
||||
buildList {
|
||||
add(SnyggEmptyRuleForAdding)
|
||||
add(SnyggAnnotationRule.Font(fontName = ""))
|
||||
FlorisImeUi.elementNames.forEach { name ->
|
||||
add(SnyggElementRule(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
val possibleRuleLabels = possibleRuleTemplates.map { rule ->
|
||||
val elementName = when (rule) {
|
||||
is SnyggElementRule -> rule.elementName
|
||||
else -> rule.decl().name
|
||||
}
|
||||
context.translateElementName(elementName, level) ?: rule
|
||||
}
|
||||
val possibleElementLabels = possibleElementNames.map { translateElementName(it, level) ?: it }
|
||||
var elementsExpanded by remember { mutableStateOf(false) }
|
||||
var elementsSelectedIndex by rememberSaveable {
|
||||
val index = possibleElementNames.indexOf(initRule.element).coerceIn(possibleElementNames.indices)
|
||||
val index = possibleRuleTemplates
|
||||
.indexOfFirst { rule ->
|
||||
val elementName = when (rule) {
|
||||
is SnyggElementRule -> rule.elementName
|
||||
else -> rule.decl().name
|
||||
}
|
||||
val initElementName = when (initRule) {
|
||||
is SnyggElementRule -> initRule.elementName
|
||||
else -> initRule.decl().name
|
||||
}
|
||||
elementName == initElementName
|
||||
}
|
||||
.coerceIn(possibleRuleTemplates.indices)
|
||||
mutableIntStateOf(index)
|
||||
}
|
||||
|
||||
val codes = rememberSaveable(saver = IntListSaver) { initRule.codes.toMutableStateList() }
|
||||
var editCodeDialogValue by rememberSaveable { mutableStateOf<Int?>(null) }
|
||||
val groups = rememberSaveable(saver = IntListSaver) { initRule.groups.toMutableStateList() }
|
||||
var shiftStateUnshifted by rememberSaveable {
|
||||
mutableStateOf(initRule.shiftStates.contains(InputShiftState.UNSHIFTED.value))
|
||||
var currentRule by rememberSaveable(elementsSelectedIndex, stateSaver = SnyggRule.NonNullSaver) {
|
||||
mutableStateOf(
|
||||
if (isAddRuleDialog) possibleRuleTemplates[elementsSelectedIndex] else initRule
|
||||
)
|
||||
}
|
||||
var shiftStateShiftedManual by rememberSaveable {
|
||||
mutableStateOf(initRule.shiftStates.contains(InputShiftState.SHIFTED_MANUAL.value))
|
||||
}
|
||||
var shiftStateShiftedAutomatic by rememberSaveable {
|
||||
mutableStateOf(initRule.shiftStates.contains(InputShiftState.SHIFTED_AUTOMATIC.value))
|
||||
}
|
||||
var shiftStateCapsLock by rememberSaveable {
|
||||
mutableStateOf(initRule.shiftStates.contains(InputShiftState.CAPS_LOCK.value))
|
||||
}
|
||||
var pressedSelector by rememberSaveable { mutableStateOf(initRule.pressedSelector) }
|
||||
var focusSelector by rememberSaveable { mutableStateOf(initRule.focusSelector) }
|
||||
var disabledSelector by rememberSaveable { mutableStateOf(initRule.disabledSelector) }
|
||||
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(if (isAddRuleDialog) {
|
||||
R.string.settings__theme_editor__add_rule
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_rule
|
||||
}),
|
||||
confirmLabel = stringRes(if (isAddRuleDialog) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}),
|
||||
title = stringRes(
|
||||
if (isAddRuleDialog) {
|
||||
R.string.settings__theme_editor__add_rule
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_rule
|
||||
}
|
||||
),
|
||||
confirmLabel = stringRes(
|
||||
if (isAddRuleDialog) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}
|
||||
),
|
||||
onConfirm = {
|
||||
if (isAddRuleDialog && elementsSelectedIndex == 0) {
|
||||
showSelectAsError = true
|
||||
} else {
|
||||
val newRule = SnyggRule(
|
||||
element = possibleElementNames[elementsSelectedIndex],
|
||||
codes = codes.toList(),
|
||||
groups = groups.toList(),
|
||||
shiftStates = buildList {
|
||||
if (shiftStateUnshifted) { add(InputShiftState.UNSHIFTED.value) }
|
||||
if (shiftStateShiftedManual) { add(InputShiftState.SHIFTED_MANUAL.value) }
|
||||
if (shiftStateShiftedAutomatic) { add(InputShiftState.SHIFTED_AUTOMATIC.value) }
|
||||
if (shiftStateCapsLock) { add(InputShiftState.CAPS_LOCK.value) }
|
||||
},
|
||||
pressedSelector = pressedSelector,
|
||||
focusSelector = focusSelector,
|
||||
disabledSelector = disabledSelector,
|
||||
)
|
||||
if (!onConfirmRule(initRule, newRule)) {
|
||||
if (!onConfirmRule(initRule, currentRule)) {
|
||||
showAlreadyExistsError = true
|
||||
}
|
||||
}
|
||||
@@ -202,154 +204,228 @@ internal fun EditRuleDialog(
|
||||
)
|
||||
}
|
||||
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_element)) {
|
||||
FlorisDropdownMenu(
|
||||
items = possibleElementLabels,
|
||||
expanded = elementsExpanded,
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_name)) {
|
||||
JetPrefDropdown(
|
||||
options = possibleRuleLabels,
|
||||
selectedOptionIndex = elementsSelectedIndex,
|
||||
onSelectOption = { elementsSelectedIndex = it },
|
||||
enabled = isAddRuleDialog,
|
||||
selectedIndex = elementsSelectedIndex,
|
||||
isError = showSelectAsError && elementsSelectedIndex == 0,
|
||||
onSelectItem = { elementsSelectedIndex = it },
|
||||
onExpandRequest = { elementsExpanded = true },
|
||||
onDismissRequest = { elementsExpanded = false },
|
||||
)
|
||||
}
|
||||
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_selectors)) {
|
||||
Row(modifier = Modifier.florisHorizontalScroll()) {
|
||||
FlorisChip(
|
||||
onClick = { pressedSelector = !pressedSelector },
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.PRESSED_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__pressed)
|
||||
(currentRule as? SnyggAnnotationRule.Font)?.apply {
|
||||
DialogProperty(text = stringRes(R.string.snygg__rule_annotation__font_name)) {
|
||||
JetPrefTextField(
|
||||
modifier = Modifier,
|
||||
value = fontName,
|
||||
onValueChange = {
|
||||
currentRule = copy(fontName = it)
|
||||
},
|
||||
selected = pressedSelector,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { focusSelector = !focusSelector },
|
||||
modifier = Modifier.padding( end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.FOCUS_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__focus)
|
||||
},
|
||||
selected = focusSelector,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { disabledSelector = !disabledSelector },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.DISABLED_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__disabled)
|
||||
},
|
||||
selected = disabledSelector,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DialogProperty(
|
||||
text = stringRes(R.string.settings__theme_editor__rule_codes),
|
||||
trailingIconTitle = {
|
||||
FlorisIconButton(
|
||||
onClick = { editCodeDialogValue = NATIVE_NULLPTR.toInt() },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = Icons.Default.Add,
|
||||
)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
text = stringRes(if (codes.isEmpty()) {
|
||||
R.string.settings__theme_editor__no_codes_defined
|
||||
// TODO: Move to toplevel @Composable function
|
||||
(currentRule as? SnyggElementRule)?.apply {
|
||||
if (elementName == SnyggEmptyRuleForAdding.elementName) {
|
||||
return@apply
|
||||
}
|
||||
fun updateCurrentRule(newSelector: SnyggSelector) {
|
||||
currentRule = if (selector == newSelector) {
|
||||
copy(selector = SnyggSelector.NONE)
|
||||
} else {
|
||||
R.string.settings__theme_editor__codes_defined
|
||||
}),
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
FlowRow {
|
||||
for (code in codes) {
|
||||
copy(selector = newSelector)
|
||||
}
|
||||
}
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_selectors)) {
|
||||
Row(modifier = Modifier.florisHorizontalScroll()) {
|
||||
//TODO: LazyRow
|
||||
FlorisChip(
|
||||
onClick = { editCodeDialogValue = code },
|
||||
text = code.toString(),
|
||||
selected = editCodeDialogValue == code,
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
onClick = { updateCurrentRule(SnyggSelector.PRESSED) },
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.PRESSED.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__pressed)
|
||||
},
|
||||
selected = selector == SnyggSelector.PRESSED,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { updateCurrentRule(SnyggSelector.FOCUS) },
|
||||
modifier = Modifier.padding( end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.FOCUS.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__focus)
|
||||
},
|
||||
selected = selector == SnyggSelector.FOCUS,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { updateCurrentRule(SnyggSelector.HOVER) },
|
||||
modifier = Modifier.padding( end = 4.dp),
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.HOVER.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__hover)
|
||||
},
|
||||
selected = selector == SnyggSelector.HOVER,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { updateCurrentRule(SnyggSelector.DISABLED) },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.DISABLED.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__disabled)
|
||||
},
|
||||
selected = selector == SnyggSelector.DISABLED,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val codes = remember(currentRule) {
|
||||
attributes[FlorisImeUi.Attr.Code] ?: emptyList()
|
||||
}
|
||||
var editCodeDialogValue by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
val initCodeValue = editCodeDialogValue
|
||||
if (initCodeValue != null) {
|
||||
EditCodeValueDialog(
|
||||
codeValue = initCodeValue,
|
||||
checkExisting = { codes.contains(it) },
|
||||
onAdd = {
|
||||
currentRule = copy(
|
||||
attributes = attributes.including(FlorisImeUi.Attr.Code to it)
|
||||
)
|
||||
},
|
||||
onDelete = {
|
||||
currentRule = copy(
|
||||
attributes = attributes.excluding(FlorisImeUi.Attr.Code to it)
|
||||
)
|
||||
},
|
||||
onDismiss = { editCodeDialogValue = null },
|
||||
)
|
||||
}
|
||||
DialogProperty(
|
||||
text = stringRes(R.string.settings__theme_editor__rule_codes),
|
||||
trailingIconTitle = {
|
||||
FlorisIconButton(
|
||||
onClick = { editCodeDialogValue = KeyCode.UNSPECIFIED.toString() },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = Icons.Default.Add,
|
||||
)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
text = stringRes(
|
||||
if (codes.isEmpty()) {
|
||||
R.string.settings__theme_editor__no_codes_defined
|
||||
} else {
|
||||
R.string.settings__theme_editor__codes_defined
|
||||
}
|
||||
),
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
FlowRow {
|
||||
for (code in codes) {
|
||||
FlorisChip(
|
||||
onClick = { editCodeDialogValue = code },
|
||||
text = code.toString(),
|
||||
selected = editCodeDialogValue == code,
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val shiftStateUnshifted = remember(currentRule) {
|
||||
attributes[FlorisImeUi.Attr.ShiftState]?.contains(InputShiftState.UNSHIFTED.attrName()) == true
|
||||
}
|
||||
val shiftStateShiftedManual = remember(currentRule) {
|
||||
attributes[FlorisImeUi.Attr.ShiftState]?.contains(InputShiftState.SHIFTED_MANUAL.attrName()) == true
|
||||
}
|
||||
val shiftStateShiftedAutomatic = remember(currentRule) {
|
||||
attributes[FlorisImeUi.Attr.ShiftState]?.contains(InputShiftState.SHIFTED_AUTOMATIC.attrName()) == true
|
||||
}
|
||||
val shiftStateCapsLock = remember(currentRule) {
|
||||
attributes[FlorisImeUi.Attr.ShiftState]?.contains(InputShiftState.CAPS_LOCK.attrName()) == true
|
||||
}
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_shift_states)) {
|
||||
FlowRow(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
FlorisChip(
|
||||
onClick = {
|
||||
currentRule = copy(
|
||||
attributes = attributes.toggling(
|
||||
FlorisImeUi.Attr.ShiftState to InputShiftState.UNSHIFTED.attrName()
|
||||
)
|
||||
)
|
||||
},
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> InputShiftState.UNSHIFTED.attrName()
|
||||
else -> stringRes(R.string.enum__input_shift_state__unshifted)
|
||||
},
|
||||
selected = shiftStateUnshifted,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = {
|
||||
currentRule = copy(
|
||||
attributes = attributes.toggling(
|
||||
FlorisImeUi.Attr.ShiftState to InputShiftState.SHIFTED_MANUAL.attrName()
|
||||
)
|
||||
)
|
||||
},
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> InputShiftState.SHIFTED_MANUAL.attrName()
|
||||
else -> stringRes(R.string.enum__input_shift_state__shifted_manual)
|
||||
},
|
||||
selected = shiftStateShiftedManual,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = {
|
||||
currentRule = copy(
|
||||
attributes = attributes.toggling(
|
||||
FlorisImeUi.Attr.ShiftState to InputShiftState.SHIFTED_AUTOMATIC.attrName()
|
||||
)
|
||||
)
|
||||
},
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> InputShiftState.SHIFTED_AUTOMATIC.attrName()
|
||||
else -> stringRes(R.string.enum__input_shift_state__shifted_automatic)
|
||||
},
|
||||
selected = shiftStateShiftedAutomatic,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = {
|
||||
currentRule = copy(
|
||||
attributes = attributes.toggling(
|
||||
FlorisImeUi.Attr.ShiftState to InputShiftState.CAPS_LOCK.attrName()
|
||||
)
|
||||
)
|
||||
},
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> InputShiftState.CAPS_LOCK.attrName()
|
||||
else -> stringRes(R.string.enum__input_shift_state__caps_lock)
|
||||
},
|
||||
selected = shiftStateCapsLock,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__rule_shift_states)) {
|
||||
FlowRow(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
FlorisChip(
|
||||
onClick = { shiftStateUnshifted = !shiftStateUnshifted },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember {
|
||||
SnyggRule.Placeholders.getKeyByValue(InputShiftState.UNSHIFTED.value)
|
||||
}
|
||||
else -> stringRes(R.string.enum__input_shift_state__unshifted)
|
||||
},
|
||||
selected = shiftStateUnshifted,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { shiftStateShiftedManual = !shiftStateShiftedManual },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember {
|
||||
SnyggRule.Placeholders.getKeyByValue(InputShiftState.SHIFTED_MANUAL.value)
|
||||
}
|
||||
else -> stringRes(R.string.enum__input_shift_state__shifted_manual)
|
||||
},
|
||||
selected = shiftStateShiftedManual,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { shiftStateShiftedAutomatic = !shiftStateShiftedAutomatic },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember {
|
||||
SnyggRule.Placeholders.getKeyByValue(InputShiftState.SHIFTED_AUTOMATIC.value)
|
||||
}
|
||||
else -> stringRes(R.string.enum__input_shift_state__shifted_automatic)
|
||||
},
|
||||
selected = shiftStateShiftedAutomatic,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { shiftStateCapsLock = !shiftStateCapsLock },
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> remember {
|
||||
SnyggRule.Placeholders.getKeyByValue(InputShiftState.CAPS_LOCK.value)
|
||||
}
|
||||
else -> stringRes(R.string.enum__input_shift_state__caps_lock)
|
||||
},
|
||||
selected = shiftStateCapsLock,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val initCodeValue = editCodeDialogValue
|
||||
if (initCodeValue != null) {
|
||||
EditCodeValueDialog(
|
||||
codeValue = initCodeValue,
|
||||
checkExisting = { codes.contains(it) },
|
||||
onAdd = { codes.add(it) },
|
||||
onDelete = { codes.remove(it) },
|
||||
onDismiss = { editCodeDialogValue = null },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun EditCodeValueDialog(
|
||||
codeValue: Int,
|
||||
checkExisting: (Int) -> Boolean,
|
||||
onAdd: (Int) -> Unit,
|
||||
onDelete: (Int) -> Unit,
|
||||
codeValue: String,
|
||||
checkExisting: (String) -> Boolean,
|
||||
onAdd: (String) -> Unit,
|
||||
onDelete: (String) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
var inputCodeString by rememberSaveable(codeValue) {
|
||||
val str = if (codeValue == 0) "" else codeValue.toString()
|
||||
val str = if (codeValue == KeyCode.UNSPECIFIED.toString()) "" else codeValue.toString()
|
||||
mutableStateOf(str)
|
||||
}
|
||||
val textKeyData = remember(inputCodeString) {
|
||||
@@ -406,6 +482,7 @@ private fun EditCodeValueDialog(
|
||||
inputCodeString = data.code.toString()
|
||||
isRecordingKey = false
|
||||
}
|
||||
|
||||
override fun onInputKeyRepeat(data: KeyData) = Unit
|
||||
override fun onInputKeyCancel(data: KeyData) = Unit
|
||||
}
|
||||
@@ -423,16 +500,20 @@ private fun EditCodeValueDialog(
|
||||
}
|
||||
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(if (codeValue == NATIVE_NULLPTR.toInt()) {
|
||||
R.string.settings__theme_editor__add_code
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_code
|
||||
}),
|
||||
confirmLabel = stringRes(if (codeValue == NATIVE_NULLPTR.toInt()) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}),
|
||||
title = stringRes(
|
||||
if (codeValue == KeyCode.UNSPECIFIED.toString()) {
|
||||
R.string.settings__theme_editor__add_code
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_code
|
||||
}
|
||||
),
|
||||
confirmLabel = stringRes(
|
||||
if (codeValue == KeyCode.UNSPECIFIED.toString()) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}
|
||||
),
|
||||
onConfirm = {
|
||||
val code = inputCodeString.trim().toIntOrNull(radix = 10)
|
||||
when {
|
||||
@@ -440,25 +521,28 @@ private fun EditCodeValueDialog(
|
||||
errorId = R.string.settings__theme_editor__code_invalid
|
||||
showError = true
|
||||
}
|
||||
code == codeValue -> {
|
||||
|
||||
code.toString() == codeValue -> {
|
||||
onDismiss()
|
||||
}
|
||||
checkExisting(code) -> {
|
||||
|
||||
checkExisting(code.toString()) -> {
|
||||
errorId = R.string.settings__theme_editor__code_already_exists
|
||||
showError = true
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (codeValue != NATIVE_NULLPTR.toInt()) {
|
||||
if (codeValue != KeyCode.UNSPECIFIED.toString()) {
|
||||
onDelete(codeValue)
|
||||
}
|
||||
onAdd(code)
|
||||
onAdd(code.toString())
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissLabel = stringRes(R.string.action__cancel),
|
||||
onDismiss = onDismiss,
|
||||
neutralLabel = if (codeValue != NATIVE_NULLPTR.toInt()) {
|
||||
neutralLabel = if (codeValue != KeyCode.UNSPECIFIED.toString()) {
|
||||
stringRes(R.string.action__delete)
|
||||
} else {
|
||||
null
|
||||
@@ -505,7 +589,7 @@ private fun EditCodeValueDialog(
|
||||
LocalTextSelectionColors.current
|
||||
}
|
||||
CompositionLocalProvider(LocalTextSelectionColors provides textSelectionColors) {
|
||||
FlorisOutlinedTextField(
|
||||
JetPrefTextField(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.weight(1f),
|
||||
@@ -514,7 +598,7 @@ private fun EditCodeValueDialog(
|
||||
inputCodeString = v
|
||||
showError = false
|
||||
},
|
||||
placeholder = when {
|
||||
placeholderText = when {
|
||||
isRecordingKey -> {
|
||||
stringRes(R.string.settings__theme_editor__code_recording_placeholder)
|
||||
}
|
||||
@@ -527,21 +611,25 @@ private fun EditCodeValueDialog(
|
||||
},
|
||||
isError = showError,
|
||||
singleLine = true,
|
||||
colors = if (isRecordingKey) {
|
||||
OutlinedTextFieldDefaults.colors(
|
||||
focusedTextColor = Color.Transparent,
|
||||
cursorColor = Color.Transparent,
|
||||
appearance = JetPrefTextFieldDefaults.filled(
|
||||
colors = if (isRecordingKey) {
|
||||
TextFieldDefaults.colors(
|
||||
focusedTextColor = Color.Transparent,
|
||||
cursorColor = Color.Transparent,
|
||||
)
|
||||
} else {
|
||||
TextFieldDefaults.colors()
|
||||
}
|
||||
),
|
||||
trailingIcon = {
|
||||
FlorisIconButton(
|
||||
onClick = { requestStartRecording() },
|
||||
icon = Icons.Default.Pageview,
|
||||
iconColor = recordingKeyColor,
|
||||
)
|
||||
} else {
|
||||
OutlinedTextFieldDefaults.colors()
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
FlorisIconButton(
|
||||
onClick = { requestStartRecording() },
|
||||
icon = Icons.Default.Pageview,
|
||||
iconColor = recordingKeyColor,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(visible = showError) {
|
||||
Text(
|
||||
@@ -573,9 +661,12 @@ private fun TextKeyDataPreviewBox(
|
||||
override val mode = KeyboardMode.NUMERIC_ADVANCED
|
||||
override fun getKeyForPos(pointerX: Float, pointerY: Float) = error("not implemented")
|
||||
override fun keys() = error("not implemented")
|
||||
override fun layout(keyboardWidth: Float, keyboardHeight: Float, desiredKey: Key,
|
||||
extendTouchBoundariesDownwards: Boolean) = error("not implemented")
|
||||
override fun layout(
|
||||
keyboardWidth: Float, keyboardHeight: Float, desiredKey: Key,
|
||||
extendTouchBoundariesDownwards: Boolean,
|
||||
) = error("not implemented")
|
||||
}
|
||||
|
||||
override fun context() = context
|
||||
}
|
||||
}
|
||||
@@ -603,20 +694,19 @@ private fun TextKeyDataPreviewBox(
|
||||
.align(Alignment.CenterVertically),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (label != null) {
|
||||
Text(
|
||||
text = label,
|
||||
fontSize = 16.sp,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
}
|
||||
if (icon != null) {
|
||||
Icon(
|
||||
modifier = Modifier.requiredSize(24.dp),
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
)
|
||||
} else if (label != null) {
|
||||
Text(
|
||||
text = label,
|
||||
fontSize = 16.sp,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
|
||||
@@ -23,9 +23,9 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import org.florisboard.lib.snygg.SnyggLevel
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceLayout
|
||||
import dev.patrickgold.jetpref.material.ui.ColorRepresentation
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||
private val FineTuneContentPadding = PaddingValues(horizontal = 8.dp)
|
||||
@@ -44,9 +44,9 @@ fun FineTuneDialog(onDismiss: () -> Unit) {
|
||||
entries = enumDisplayEntriesOf(SnyggLevel::class),
|
||||
)
|
||||
ListPreference(
|
||||
listPref = prefs.theme.editorDisplayColorsAs,
|
||||
title = stringRes(R.string.settings__theme_editor__fine_tune__display_colors_as),
|
||||
entries = enumDisplayEntriesOf(DisplayColorsAs::class),
|
||||
listPref = prefs.theme.editorColorRepresentation,
|
||||
title = stringRes(R.string.settings__theme_editor__fine_tune__color_representation),
|
||||
entries = enumDisplayEntriesOf(ColorRepresentation::class),
|
||||
)
|
||||
ListPreference(
|
||||
listPref = prefs.theme.editorDisplayKbdAfterDialogs,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.florisboard.lib.snygg
|
||||
package dev.patrickgold.florisboard.app.settings.theme
|
||||
|
||||
/**
|
||||
* SnyggLevel indicates if a rule property is intended to be edited by all users (BASIC) or only by advanced users
|
||||
@@ -26,29 +26,64 @@ import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.shape.CutCornerShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.FormatAlignLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.FormatAlignRight
|
||||
import androidx.compose.material.icons.automirrored.filled.WrapText
|
||||
import androidx.compose.material.icons.filled.AttachFile
|
||||
import androidx.compose.material.icons.filled.CheckBox
|
||||
import androidx.compose.material.icons.filled.CheckBoxOutlineBlank
|
||||
import androidx.compose.material.icons.filled.FontDownload
|
||||
import androidx.compose.material.icons.filled.FormatAlignCenter
|
||||
import androidx.compose.material.icons.filled.FormatAlignJustify
|
||||
import androidx.compose.material.icons.filled.FormatBold
|
||||
import androidx.compose.material.icons.filled.FormatItalic
|
||||
import androidx.compose.material.icons.filled.FormatSize
|
||||
import androidx.compose.material.icons.filled.FormatStrikethrough
|
||||
import androidx.compose.material.icons.filled.FormatUnderlined
|
||||
import androidx.compose.material.icons.filled.Link
|
||||
import androidx.compose.material.icons.filled.OpenInFull
|
||||
import androidx.compose.material.icons.filled.Padding
|
||||
import androidx.compose.material.icons.filled.Straighten
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDefinedVarValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDpSizeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggMaterialYouValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggStaticColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSpSizeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggValue
|
||||
import dev.patrickgold.jetpref.material.ui.checkeredBackground
|
||||
import org.florisboard.lib.color.ColorMappings
|
||||
import org.florisboard.lib.color.getColor
|
||||
import org.florisboard.lib.snygg.value.SnyggContentScaleValue
|
||||
import org.florisboard.lib.snygg.value.SnyggCustomFontFamilyValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDynamicDarkColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDynamicLightColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggFontStyleValue
|
||||
import org.florisboard.lib.snygg.value.SnyggFontWeightValue
|
||||
import org.florisboard.lib.snygg.value.SnyggGenericFontFamilyValue
|
||||
import org.florisboard.lib.snygg.value.SnyggNoValue
|
||||
import org.florisboard.lib.snygg.value.SnyggPaddingValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextAlignValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextDecorationLineValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextOverflowValue
|
||||
import org.florisboard.lib.snygg.value.SnyggUriValue
|
||||
import org.florisboard.lib.snygg.value.SnyggYesValue
|
||||
|
||||
object SnyggValueIcon {
|
||||
interface Spec {
|
||||
@@ -86,13 +121,51 @@ internal fun SnyggValueIcon(
|
||||
modifier: Modifier = Modifier,
|
||||
spec: SnyggValueIcon.Spec = SnyggValueIcon.Normal,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val context = LocalContext.current
|
||||
val accentColor by prefs.theme.accentColor.observeAsState()
|
||||
|
||||
when (value) {
|
||||
is SnyggSolidColorValue -> {
|
||||
is SnyggStaticColorValue -> {
|
||||
SnyggValueColorBox(modifier = modifier, spec = spec, backgroundColor = value.color)
|
||||
}
|
||||
is SnyggDynamicLightColorValue -> {
|
||||
val colorScheme = ColorMappings.dynamicLightColorScheme(context, accentColor)
|
||||
SnyggValueColorBox(modifier = modifier, spec = spec, backgroundColor = colorScheme.getColor(value.colorName))
|
||||
}
|
||||
is SnyggDynamicDarkColorValue -> {
|
||||
val colorScheme = ColorMappings.dynamicDarkColorScheme(context, accentColor)
|
||||
SnyggValueColorBox(modifier = modifier, spec = spec, backgroundColor = colorScheme.getColor(value.colorName))
|
||||
}
|
||||
|
||||
is SnyggMaterialYouValue -> {
|
||||
SnyggValueColorBox(modifier = modifier, spec = spec, backgroundColor = value.loadColor(LocalContext.current))
|
||||
is SnyggGenericFontFamilyValue, is SnyggCustomFontFamilyValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.FontDownload,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
is SnyggFontStyleValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.FormatItalic,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
is SnyggFontWeightValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.FormatBold,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
is SnyggPaddingValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.Padding,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
is SnyggShapeValue -> {
|
||||
@@ -102,6 +175,7 @@ internal fun SnyggValueIcon(
|
||||
.border(spec.borderWith, MaterialTheme.colorScheme.onBackground, value.alwaysPercentShape())
|
||||
)
|
||||
}
|
||||
|
||||
is SnyggDpSizeValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
@@ -116,6 +190,37 @@ internal fun SnyggValueIcon(
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
is SnyggTextAlignValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = when (value.textAlign) {
|
||||
TextAlign.Left, TextAlign.Start -> Icons.AutoMirrored.Default.FormatAlignLeft
|
||||
TextAlign.Right, TextAlign.End -> Icons.AutoMirrored.Default.FormatAlignRight
|
||||
TextAlign.Justify -> Icons.Default.FormatAlignJustify
|
||||
else -> Icons.Default.FormatAlignCenter
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
is SnyggTextDecorationLineValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = when (value.textDecoration) {
|
||||
TextDecoration.LineThrough -> Icons.Default.FormatStrikethrough
|
||||
else -> Icons.Default.FormatUnderlined
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
is SnyggTextOverflowValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.AutoMirrored.Default.WrapText,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
is SnyggDefinedVarValue -> {
|
||||
val realValue = definedVariables[value.key]
|
||||
if (realValue == null) {
|
||||
@@ -150,6 +255,37 @@ internal fun SnyggValueIcon(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is SnyggUriValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.AttachFile,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
is SnyggContentScaleValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.OpenInFull,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
is SnyggYesValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.FormatBold,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
is SnyggNoValue -> {
|
||||
Icon(
|
||||
modifier = modifier.requiredSize(spec.iconSize),
|
||||
imageVector = Icons.Default.CheckBoxOutlineBlank,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Render nothing
|
||||
}
|
||||
|
||||
@@ -36,11 +36,16 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
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.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material.icons.filled.Tune
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
@@ -53,11 +58,8 @@ import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -71,17 +73,18 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.apptheme.Shapes
|
||||
import dev.patrickgold.florisboard.app.ext.ExtensionComponentView
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUiSpec
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponentEditor
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionEditor
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeManager
|
||||
import dev.patrickgold.florisboard.ime.theme.extPreviewTheme
|
||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
|
||||
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.PreviewKeyboardField
|
||||
import dev.patrickgold.florisboard.lib.compose.Validation
|
||||
import dev.patrickgold.florisboard.lib.compose.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.lib.compose.florisVerticalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.rememberPreviewFieldController
|
||||
@@ -93,26 +96,46 @@ import dev.patrickgold.florisboard.themeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefTextField
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.showLongToast
|
||||
import org.florisboard.lib.kotlin.io.readJson
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
import org.florisboard.lib.snygg.SnyggLevel
|
||||
import org.florisboard.lib.snygg.SnyggPropertySetEditor
|
||||
import org.florisboard.lib.snygg.SnyggPropertySetSpec
|
||||
import org.florisboard.lib.snygg.SnyggAnnotationRule
|
||||
import org.florisboard.lib.snygg.SnyggElementRule
|
||||
import org.florisboard.lib.snygg.SnyggJsonConfiguration
|
||||
import org.florisboard.lib.snygg.SnyggMultiplePropertySetsEditor
|
||||
import org.florisboard.lib.snygg.SnyggRule
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.SnyggSinglePropertySetEditor
|
||||
import org.florisboard.lib.snygg.SnyggSpec
|
||||
import org.florisboard.lib.snygg.SnyggSpecDecl
|
||||
import org.florisboard.lib.snygg.SnyggStylesheet
|
||||
import org.florisboard.lib.snygg.SnyggStylesheetEditor
|
||||
import org.florisboard.lib.snygg.SnyggStylesheetJsonConfig
|
||||
import org.florisboard.lib.snygg.definedVariablesRule
|
||||
import org.florisboard.lib.snygg.isDefinedVariablesRule
|
||||
import org.florisboard.lib.snygg.ui.Saver
|
||||
import kotlin.Boolean
|
||||
import kotlin.String
|
||||
|
||||
internal val IntListSaver = Saver<SnapshotStateList<Int>, ArrayList<Int>>(
|
||||
save = { ArrayList(it) },
|
||||
restore = { it.toMutableStateList() },
|
||||
internal val PrettyPrintConfig = SnyggJsonConfiguration.of(
|
||||
prettyPrint = true,
|
||||
prettyPrintIndent = " ",
|
||||
)
|
||||
|
||||
private val LenientConfig = SnyggJsonConfiguration.of(
|
||||
ignoreMissingSchema = true,
|
||||
ignoreInvalidSchema = true,
|
||||
ignoreUnsupportedSchema = true,
|
||||
ignoreInvalidRules = true,
|
||||
ignoreInvalidProperties = true,
|
||||
ignoreInvalidValues = true,
|
||||
)
|
||||
|
||||
private enum class StylesheetLoadingStrategy {
|
||||
TRY_LOAD_OR_ASK_ON_CONFLICT, // default state
|
||||
TRY_LOAD_OR_EMPTY, // user chose to not auto-fix errors
|
||||
TRY_LOAD_OR_PARSE_LENIENT; // user chose to auto-fix errors
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ThemeEditorScreen(
|
||||
@@ -130,35 +153,66 @@ fun ThemeEditorScreen(
|
||||
val scope = rememberCoroutineScope()
|
||||
val previewFieldController = rememberPreviewFieldController().also { it.isVisible = true }
|
||||
|
||||
val stylesheetEditor = remember {
|
||||
var stylesheetLoadingStrategy by rememberSaveable {
|
||||
mutableStateOf(StylesheetLoadingStrategy.TRY_LOAD_OR_ASK_ON_CONFLICT)
|
||||
}
|
||||
var stylesheetEditorFailure by remember { mutableStateOf<Throwable?>(null) }
|
||||
val stylesheetEditor = remember(stylesheetLoadingStrategy) {
|
||||
editor.stylesheetEditor ?: run {
|
||||
stylesheetEditorFailure = null
|
||||
val stylesheetPath = editor.stylesheetPath()
|
||||
editor.stylesheetPathOnLoad = stylesheetPath
|
||||
val stylesheetFile = workspace.extDir.subFile(stylesheetPath)
|
||||
val stylesheetEditor = if (stylesheetFile.exists()) {
|
||||
try {
|
||||
stylesheetFile.readJson<SnyggStylesheet>(SnyggStylesheetJsonConfig).edit()
|
||||
} catch (e: Throwable) {
|
||||
SnyggStylesheetEditor()
|
||||
val stylesheetJson = stylesheetFile.readText()
|
||||
val config = when (stylesheetLoadingStrategy) {
|
||||
StylesheetLoadingStrategy.TRY_LOAD_OR_PARSE_LENIENT -> LenientConfig
|
||||
else -> PrettyPrintConfig
|
||||
}
|
||||
SnyggStylesheet.fromJson(stylesheetJson, config).getOrThrow().edit(CustomRuleComparator)
|
||||
} catch (error: Throwable) {
|
||||
stylesheetEditorFailure = when (stylesheetLoadingStrategy) {
|
||||
StylesheetLoadingStrategy.TRY_LOAD_OR_ASK_ON_CONFLICT -> error
|
||||
else -> null
|
||||
}
|
||||
SnyggStylesheetEditor(SnyggStylesheet.SCHEMA_V2, comparator = CustomRuleComparator)
|
||||
}
|
||||
} else {
|
||||
SnyggStylesheetEditor()
|
||||
}
|
||||
if (stylesheetEditor.rules.none { (rule, _) -> rule.isDefinedVariablesRule() }) {
|
||||
stylesheetEditor.rules[SnyggRule.definedVariablesRule()] = SnyggPropertySetEditor()
|
||||
SnyggStylesheetEditor(SnyggStylesheet.SCHEMA_V2, comparator = CustomRuleComparator)
|
||||
}
|
||||
stylesheetEditor.rules.putIfAbsent(SnyggAnnotationRule.Defines, SnyggSinglePropertySetEditor())
|
||||
stylesheetEditor
|
||||
}.also { editor.stylesheetEditor = it }
|
||||
}
|
||||
|
||||
val definedVariables = remember(stylesheetEditor.rules) {
|
||||
stylesheetEditor.rules.firstNotNullOfOrNull { (rule, propertySet) ->
|
||||
if (rule is SnyggAnnotationRule.Defines && propertySet is SnyggSinglePropertySetEditor) {
|
||||
propertySet.properties
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: emptyMap()
|
||||
}
|
||||
|
||||
val fontNames = remember(stylesheetEditor.rules) {
|
||||
stylesheetEditor.rules.mapNotNull { (rule, _) ->
|
||||
if (rule is SnyggAnnotationRule.Font) {
|
||||
rule.fontName
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val snyggLevel by prefs.theme.editorLevel.observeAsState()
|
||||
val displayColorsAs by prefs.theme.editorDisplayColorsAs.observeAsState()
|
||||
val colorRepresentation by prefs.theme.editorColorRepresentation.observeAsState()
|
||||
val displayKbdAfterDialogs by prefs.theme.editorDisplayKbdAfterDialogs.observeAsState()
|
||||
var oldFocusState by remember { mutableStateOf(false) }
|
||||
var snyggRuleToEdit by rememberSaveable(stateSaver = SnyggRule.Saver) { mutableStateOf(null) }
|
||||
var snyggPropertyToEdit by remember { mutableStateOf<PropertyInfo?>(null) }
|
||||
var snyggPropertySetForEditing = remember<SnyggPropertySetEditor?> { null }
|
||||
var snyggPropertySetSpecForEditing = remember<SnyggPropertySetSpec?> { null }
|
||||
var snyggPropertySetForEditing = remember<SnyggSinglePropertySetEditor?> { null }
|
||||
var showEditComponentMetaDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var showFineTuneDialog by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
@@ -198,6 +252,33 @@ fun ThemeEditorScreen(
|
||||
}
|
||||
|
||||
content {
|
||||
stylesheetEditorFailure?.let { failure ->
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(R.string.settings__theme_editor__stylesheet_error_title),
|
||||
confirmLabel = stringRes(R.string.action__yes),
|
||||
onConfirm = {
|
||||
editor.stylesheetEditor = null
|
||||
stylesheetLoadingStrategy = StylesheetLoadingStrategy.TRY_LOAD_OR_PARSE_LENIENT
|
||||
},
|
||||
dismissLabel = stringRes(R.string.action__no),
|
||||
onDismiss = {
|
||||
editor.stylesheetEditor = null
|
||||
stylesheetLoadingStrategy = StylesheetLoadingStrategy.TRY_LOAD_OR_EMPTY
|
||||
},
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
text = failure.message.toString(),
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
Text(
|
||||
text = stringRes(R.string.settings__theme_editor__stylesheet_error_description),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler {
|
||||
handleBackPress()
|
||||
}
|
||||
@@ -229,23 +310,15 @@ fun ThemeEditorScreen(
|
||||
|
||||
DisposableEffect(workspace.version) {
|
||||
themeManager.previewThemeInfo = ThemeManager.ThemeInfo.DEFAULT.copy(
|
||||
stylesheet = stylesheetEditor.build().compileToFullyQualified(FlorisImeUiSpec),
|
||||
name = extPreviewTheme(System.currentTimeMillis().toString()),
|
||||
stylesheet = stylesheetEditor.build(),
|
||||
loadedDir = workspace.extDir,
|
||||
)
|
||||
onDispose {
|
||||
themeManager.previewThemeInfo = null
|
||||
}
|
||||
}
|
||||
|
||||
val definedVariables = remember(stylesheetEditor.rules) {
|
||||
stylesheetEditor.rules.firstNotNullOfOrNull { (rule, propertySet) ->
|
||||
if (rule.isDefinedVariablesRule()) {
|
||||
propertySet.properties
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: emptyMap()
|
||||
}
|
||||
|
||||
// TODO: (priority = low)
|
||||
// Floris scrollbar does not like lazy lists with non-constant item heights.
|
||||
// Consider building a custom scrollbar tailored for this list specifically.
|
||||
@@ -263,7 +336,7 @@ fun ThemeEditorScreen(
|
||||
onEditBtnClick = { showEditComponentMetaDialog = true },
|
||||
)
|
||||
if (stylesheetEditor.rules.isEmpty() ||
|
||||
(stylesheetEditor.rules.size == 1 && stylesheetEditor.rules.keys.all { it.isDefinedVariablesRule() })
|
||||
(stylesheetEditor.rules.size == 1 && stylesheetEditor.rules.all { (rule, _) -> rule == SnyggAnnotationRule.Defines })
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||
@@ -274,9 +347,9 @@ fun ThemeEditorScreen(
|
||||
}
|
||||
}
|
||||
|
||||
items(stylesheetEditor.rules.entries.toList()) { (rule, propertySet) -> key(rule) {
|
||||
val isVariablesRule = rule.isDefinedVariablesRule()
|
||||
val propertySetSpec = FlorisImeUiSpec.propertySetSpec(rule.element)
|
||||
items(stylesheetEditor.rules.toList()) { (rule, propertySet) -> key(rule) {
|
||||
val propertySetSpec = SnyggSpec.propertySetSpecOf(rule)
|
||||
val isVariablesRule = rule == SnyggAnnotationRule.Defines
|
||||
FlorisOutlinedBox(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
||||
@@ -291,33 +364,129 @@ fun ThemeEditorScreen(
|
||||
snyggRuleToEdit = rule
|
||||
},
|
||||
onAddPropertyBtnClick = {
|
||||
snyggPropertySetForEditing = propertySet
|
||||
snyggPropertySetSpecForEditing = propertySetSpec
|
||||
snyggPropertyToEdit = SnyggEmptyPropertyInfoForAdding
|
||||
when(propertySet) {
|
||||
is SnyggMultiplePropertySetsEditor -> {
|
||||
workspace.update {
|
||||
propertySet.sets.add(SnyggSinglePropertySetEditor())
|
||||
}
|
||||
}
|
||||
is SnyggSinglePropertySetEditor -> {
|
||||
snyggPropertySetForEditing = propertySet
|
||||
snyggPropertyToEdit = SnyggEmptyPropertyInfoForAdding.copy(
|
||||
rule = rule,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
if (isVariablesRule) {
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 8.dp, start = 16.dp, end = 16.dp),
|
||||
text = stringRes(R.string.snygg__rule_element__defines_description),
|
||||
text = stringRes(R.string.snygg__rule_annotation__defines_description),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
}
|
||||
for ((propertyName, propertyValue) in propertySet.properties) {
|
||||
val propertySpec = propertySetSpec?.propertySpec(propertyName)
|
||||
if (propertySpec != null && propertySpec.level <= snyggLevel || isVariablesRule) {
|
||||
JetPrefListItem(
|
||||
modifier = Modifier.rippleClickable {
|
||||
snyggPropertySetForEditing = propertySet
|
||||
snyggPropertySetSpecForEditing = propertySetSpec
|
||||
snyggPropertyToEdit = PropertyInfo(propertyName, propertyValue)
|
||||
},
|
||||
text = translatePropertyName(propertyName, snyggLevel),
|
||||
secondaryText = translatePropertyValue(propertyValue, snyggLevel, displayColorsAs),
|
||||
singleLineSecondaryText = true,
|
||||
trailing = { SnyggValueIcon(propertyValue, definedVariables) },
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun SinglePropertySetEditor(
|
||||
propertySet: SnyggSinglePropertySetEditor,
|
||||
) {
|
||||
for ((propertyName, propertySpec) in propertySetSpec?.properties.orEmpty()) {
|
||||
if (propertySpec.required && !propertySet.properties.containsKey(propertyName)) {
|
||||
FlorisOutlinedBox(title = "Errors", modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp)) {
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp),
|
||||
text = "Required property '$propertyName' does not exist",
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
for ((propertyName, propertyValue) in propertySet.properties) {
|
||||
if (true /*propertySpec != null && propertySpec.level <= snyggLevel*/ || isVariablesRule) {
|
||||
JetPrefListItem(
|
||||
modifier = Modifier.rippleClickable {
|
||||
snyggPropertySetForEditing = propertySet
|
||||
snyggPropertyToEdit = PropertyInfo(rule, propertyName, propertyValue)
|
||||
},
|
||||
text = context.translatePropertyName(propertyName, snyggLevel),
|
||||
secondaryText = context.translatePropertyValue(propertyValue, snyggLevel, colorRepresentation),
|
||||
singleLineSecondaryText = true,
|
||||
trailing = { SnyggValueIcon(propertyValue, definedVariables) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (propertySet) {
|
||||
is SnyggSinglePropertySetEditor -> {
|
||||
SinglePropertySetEditor(propertySet)
|
||||
}
|
||||
is SnyggMultiplePropertySetsEditor -> {
|
||||
val sets = propertySet.sets
|
||||
sets.forEachIndexed { propertySetIndex, propertySet ->
|
||||
key(propertySet.uuid) {
|
||||
FlorisOutlinedBox(Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp)) {
|
||||
Row {
|
||||
Text("Source set", Modifier
|
||||
.padding(start = 16.dp)
|
||||
.align(Alignment.CenterVertically))
|
||||
Spacer(Modifier.weight(1f))
|
||||
FlorisIconButton(
|
||||
onClick = {
|
||||
workspace.update {
|
||||
if (propertySetIndex > 0) {
|
||||
val set = sets.removeAt(propertySetIndex)
|
||||
sets.add(propertySetIndex - 1, set)
|
||||
}
|
||||
}
|
||||
},
|
||||
icon = Icons.Default.KeyboardArrowUp,
|
||||
iconColor = MaterialTheme.colorScheme.primary,
|
||||
iconModifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
enabled = propertySetIndex > 0,
|
||||
)
|
||||
FlorisIconButton(
|
||||
onClick = {
|
||||
workspace.update {
|
||||
if (propertySetIndex + 1 < sets.size) {
|
||||
val set = sets.removeAt(propertySetIndex)
|
||||
sets.add(propertySetIndex + 1, set)
|
||||
}
|
||||
}
|
||||
},
|
||||
icon = Icons.Default.KeyboardArrowDown,
|
||||
iconColor = MaterialTheme.colorScheme.primary,
|
||||
iconModifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
enabled = propertySetIndex + 1 < sets.size,
|
||||
)
|
||||
FlorisIconButton(
|
||||
onClick = {
|
||||
workspace.update {
|
||||
sets.removeAt(propertySetIndex)
|
||||
}
|
||||
},
|
||||
icon = Icons.Default.Delete,
|
||||
iconColor = MaterialTheme.colorScheme.primary,
|
||||
iconModifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
FlorisIconButton(
|
||||
onClick = {
|
||||
snyggPropertySetForEditing = propertySet
|
||||
snyggPropertyToEdit = SnyggEmptyPropertyInfoForAdding.copy(
|
||||
rule = rule,
|
||||
)
|
||||
},
|
||||
icon = Icons.Default.Add,
|
||||
iconColor = MaterialTheme.colorScheme.primary,
|
||||
iconModifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
}
|
||||
SinglePropertySetEditor(propertySet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,7 +538,14 @@ fun ThemeEditorScreen(
|
||||
true
|
||||
}
|
||||
oldRule == SnyggEmptyRuleForAdding -> {
|
||||
rules[newRule] = SnyggPropertySetEditor()
|
||||
when (SnyggSpec.propertySetSpecOf(newRule)!!.type) {
|
||||
SnyggSpecDecl.PropertySet.Type.SINGLE_SET -> {
|
||||
rules[newRule] = SnyggSinglePropertySetEditor()
|
||||
}
|
||||
SnyggSpecDecl.PropertySet.Type.MULTIPLE_SETS -> {
|
||||
rules[newRule] = SnyggMultiplePropertySetsEditor()
|
||||
}
|
||||
}
|
||||
snyggRuleToEdit = null
|
||||
scope.launch {
|
||||
lazyListState.animateScrollToItem(index = rules.keys.indexOf(newRule))
|
||||
@@ -396,11 +572,12 @@ fun ThemeEditorScreen(
|
||||
val propertyToEdit = snyggPropertyToEdit
|
||||
if (propertyToEdit != null) {
|
||||
EditPropertyDialog(
|
||||
propertySetSpec = snyggPropertySetSpecForEditing,
|
||||
initProperty = propertyToEdit,
|
||||
level = snyggLevel,
|
||||
displayColorsAs = displayColorsAs,
|
||||
colorRepresentation = colorRepresentation,
|
||||
definedVariables = definedVariables,
|
||||
fontNames = fontNames,
|
||||
workspace = workspace,
|
||||
onConfirmNewValue = { name, value ->
|
||||
val properties = snyggPropertySetForEditing?.properties ?: return@EditPropertyDialog false
|
||||
if (propertyToEdit == SnyggEmptyPropertyInfoForAdding && properties.containsKey(name)) {
|
||||
@@ -441,8 +618,6 @@ private fun ComponentMetaEditorDialog(
|
||||
var authors by rememberSaveable { mutableStateOf(editor.authors.joinToString("\n")) }
|
||||
val authorsValidation = rememberValidationResult(ExtensionValidation.ComponentAuthors, authors)
|
||||
var isNightTheme by rememberSaveable { mutableStateOf(editor.isNightTheme) }
|
||||
var isBorderless by rememberSaveable { mutableStateOf(editor.isBorderless) }
|
||||
val isMaterialYouAware by rememberSaveable { mutableStateOf(editor.isMaterialYouAware) }
|
||||
var stylesheetPath by rememberSaveable { mutableStateOf(editor.stylesheetPath) }
|
||||
val stylesheetPathValidation = rememberValidationResult(ExtensionValidation.ThemeComponentStylesheetPath, stylesheetPath)
|
||||
|
||||
@@ -464,8 +639,6 @@ private fun ComponentMetaEditorDialog(
|
||||
editor.label = label.trim()
|
||||
editor.authors = authors.lines().map { it.trim() }.filter { it.isNotBlank() }
|
||||
editor.isNightTheme = isNightTheme
|
||||
editor.isBorderless = isBorderless
|
||||
editor.isMaterialYouAware = isMaterialYouAware
|
||||
editor.stylesheetPath = stylesheetPath.trim()
|
||||
}
|
||||
onConfirm()
|
||||
@@ -477,31 +650,28 @@ private fun ComponentMetaEditorDialog(
|
||||
) {
|
||||
Column {
|
||||
DialogProperty(text = stringRes(R.string.ext__meta__id)) {
|
||||
FlorisOutlinedTextField(
|
||||
JetPrefTextField(
|
||||
value = id,
|
||||
onValueChange = { id = it },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii),
|
||||
singleLine = true,
|
||||
showValidationError = showValidationErrors,
|
||||
validationResult = idValidation,
|
||||
)
|
||||
Validation(showValidationErrors, idValidation)
|
||||
}
|
||||
DialogProperty(text = stringRes(R.string.ext__meta__label)) {
|
||||
FlorisOutlinedTextField(
|
||||
JetPrefTextField(
|
||||
value = label,
|
||||
onValueChange = { label = it },
|
||||
singleLine = true,
|
||||
showValidationError = showValidationErrors,
|
||||
validationResult = labelValidation,
|
||||
)
|
||||
Validation(showValidationErrors, labelValidation)
|
||||
}
|
||||
DialogProperty(text = stringRes(R.string.ext__meta__authors)) {
|
||||
FlorisOutlinedTextField(
|
||||
JetPrefTextField(
|
||||
value = authors,
|
||||
onValueChange = { authors = it },
|
||||
showValidationError = showValidationErrors,
|
||||
validationResult = authorsValidation,
|
||||
)
|
||||
Validation(showValidationErrors, authorsValidation)
|
||||
}
|
||||
JetPrefListItem(
|
||||
modifier = Modifier.toggleable(isNightTheme) { isNightTheme = it },
|
||||
@@ -509,28 +679,21 @@ private fun ComponentMetaEditorDialog(
|
||||
trailing = {
|
||||
Switch(checked = isNightTheme, onCheckedChange = null)
|
||||
},
|
||||
)
|
||||
JetPrefListItem(
|
||||
modifier = Modifier.toggleable(isBorderless) { isBorderless = it },
|
||||
text = stringRes(R.string.settings__theme_editor__component_meta_is_borderless),
|
||||
trailing = {
|
||||
Switch(checked = isBorderless, onCheckedChange = null)
|
||||
},
|
||||
colors = ListItemDefaults.colors(containerColor = AlertDialogDefaults.containerColor)
|
||||
)
|
||||
DialogProperty(text = stringRes(R.string.settings__theme_editor__component_meta_stylesheet_path)) {
|
||||
FlorisOutlinedTextField(
|
||||
JetPrefTextField(
|
||||
value = stylesheetPath,
|
||||
onValueChange = { stylesheetPath = it },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii),
|
||||
singleLine = true,
|
||||
placeholder = if (stylesheetPath.isEmpty()) {
|
||||
placeholderText = if (stylesheetPath.isEmpty()) {
|
||||
ThemeExtensionComponent.defaultStylesheetPath(id.trim())
|
||||
} else {
|
||||
null
|
||||
},
|
||||
showValidationError = showValidationErrors,
|
||||
validationResult = stylesheetPathValidation,
|
||||
)
|
||||
Validation(showValidationErrors, stylesheetPathValidation)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -544,6 +707,8 @@ private fun SnyggRuleRow(
|
||||
onEditRuleBtnClick: () -> Unit,
|
||||
onAddPropertyBtnClick: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
@Composable
|
||||
fun Selector(text: String) {
|
||||
Text(
|
||||
@@ -580,38 +745,53 @@ private fun SnyggRuleRow(
|
||||
.weight(1f)
|
||||
.padding(vertical = 8.dp, horizontal = 10.dp),
|
||||
) {
|
||||
Text(
|
||||
text = translateElementName(rule, level),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
if (rule.pressedSelector) {
|
||||
Selector(text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.PRESSED_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__pressed)
|
||||
})
|
||||
if (rule is SnyggElementRule) {
|
||||
Text(
|
||||
text = context.translateElementName(rule, level),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
if (rule.selector == SnyggSelector.PRESSED) {
|
||||
Selector(
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.PRESSED.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__pressed)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (rule.selector == SnyggSelector.FOCUS) {
|
||||
Selector(
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.FOCUS.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__focus)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (rule.selector == SnyggSelector.HOVER) {
|
||||
Selector(
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.HOVER.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__hover)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (rule.selector == SnyggSelector.DISABLED) {
|
||||
Selector(
|
||||
text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggSelector.DISABLED.id
|
||||
else -> stringRes(R.string.snygg__rule_selector__disabled)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
if (rule.focusSelector) {
|
||||
Selector(text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.FOCUS_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__focus)
|
||||
})
|
||||
for ((attrKey, attrValue) in rule.attributes) {
|
||||
AttributesList(text = attrKey, list = attrValue.toString())
|
||||
}
|
||||
if (rule.disabledSelector) {
|
||||
Selector(text = when (level) {
|
||||
SnyggLevel.DEVELOPER -> SnyggRule.DISABLED_SELECTOR
|
||||
else -> stringRes(R.string.snygg__rule_selector__disabled)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (rule.codes.isNotEmpty()) {
|
||||
AttributesList(text = "code", list = remember(rule.codes) { rule.codes.toString() })
|
||||
}
|
||||
if (rule.shiftStates.isNotEmpty()) {
|
||||
AttributesList(text = "shiftstate", list = remember(rule.shiftStates) { rule.shiftStates.toString() })
|
||||
} else {
|
||||
Text(text = rule.toString())
|
||||
}
|
||||
}
|
||||
if (showEditBtn) {
|
||||
@@ -645,10 +825,31 @@ internal fun DialogProperty(
|
||||
.weight(1f)
|
||||
.padding(vertical = 8.dp),
|
||||
text = text,
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
trailingIconTitle()
|
||||
}
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
private object CustomRuleComparator : Comparator<SnyggRule> {
|
||||
@Suppress("IfThenToElvis")
|
||||
override fun compare(a: SnyggRule, b: SnyggRule): Int {
|
||||
return if (a !is SnyggElementRule || b !is SnyggElementRule || a.elementName == b.elementName) {
|
||||
a.compareTo(b)
|
||||
} else {
|
||||
val aOrdinal = FlorisImeUi.elementNamesToOrdinals[a.elementName]
|
||||
val bOrdinal = FlorisImeUi.elementNamesToOrdinals[b.elementName]
|
||||
if (aOrdinal == null && bOrdinal == null) {
|
||||
a.elementName.compareTo(b.elementName)
|
||||
} else if (bOrdinal == null) {
|
||||
-1
|
||||
} else if (aOrdinal == null) {
|
||||
1
|
||||
} else {
|
||||
aOrdinal.compareTo(bOrdinal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,134 +16,108 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.settings.theme
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.UnicodeCtrlChar
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.material.ui.ColorRepresentation
|
||||
import org.florisboard.lib.kotlin.simpleNameOrEnclosing
|
||||
import org.florisboard.lib.snygg.Snygg
|
||||
import org.florisboard.lib.snygg.SnyggLevel
|
||||
import org.florisboard.lib.snygg.SnyggRule
|
||||
import org.florisboard.lib.snygg.value.RgbaColor
|
||||
import org.florisboard.lib.snygg.SnyggElementRule
|
||||
import org.florisboard.lib.snygg.value.SnyggCircleShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggCustomFontFamilyValue
|
||||
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggCutCornerPercentShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDefinedVarValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDpSizeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggExplicitInheritValue
|
||||
import org.florisboard.lib.snygg.value.SnyggImplicitInheritValue
|
||||
import org.florisboard.lib.snygg.value.SnyggMaterialYouDarkColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDynamicDarkColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDynamicLightColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggFontStyleValue
|
||||
import org.florisboard.lib.snygg.value.SnyggFontWeightValue
|
||||
import org.florisboard.lib.snygg.value.SnyggGenericFontFamilyValue
|
||||
import org.florisboard.lib.snygg.value.SnyggInheritValue
|
||||
import org.florisboard.lib.snygg.value.SnyggNoValue
|
||||
import org.florisboard.lib.snygg.value.SnyggContentScaleValue
|
||||
import org.florisboard.lib.snygg.value.SnyggPaddingValue
|
||||
import org.florisboard.lib.snygg.value.SnyggPercentageSizeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRectangleShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRoundedCornerPercentShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSpSizeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggStaticColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextAlignValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextDecorationLineValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextMaxLinesValue
|
||||
import org.florisboard.lib.snygg.value.SnyggTextOverflowValue
|
||||
import org.florisboard.lib.snygg.value.SnyggUndefinedValue
|
||||
import org.florisboard.lib.snygg.value.SnyggUriValue
|
||||
import org.florisboard.lib.snygg.value.SnyggValue
|
||||
import org.florisboard.lib.snygg.value.SnyggValueEncoder
|
||||
import kotlin.math.roundToInt
|
||||
import org.florisboard.lib.snygg.value.SnyggYesValue
|
||||
|
||||
@Composable
|
||||
internal fun translateElementName(rule: SnyggRule, level: SnyggLevel): String {
|
||||
return translateElementName(rule.element, level) ?: remember {
|
||||
buildString {
|
||||
if (rule.isAnnotation) {
|
||||
append(SnyggRule.ANNOTATION_MARKER)
|
||||
}
|
||||
append(rule.element)
|
||||
}
|
||||
internal fun Context.translateElementName(rule: SnyggElementRule, level: SnyggLevel): String {
|
||||
return translateElementName(rule.elementName, level) ?: rule.elementName
|
||||
}
|
||||
|
||||
internal fun Context.translateElementName(element: String, level: SnyggLevel): String? {
|
||||
return when (level) {
|
||||
SnyggLevel.DEVELOPER -> null
|
||||
else -> FlorisImeUi.elementNamesToTranslation[element]?.let { getString(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun translateElementName(element: String, level: SnyggLevel): String? {
|
||||
return when (level) {
|
||||
SnyggLevel.DEVELOPER -> null
|
||||
else -> when (element) {
|
||||
"defines" -> R.string.snygg__rule_element__defines
|
||||
FlorisImeUi.Keyboard -> R.string.snygg__rule_element__keyboard
|
||||
FlorisImeUi.Key -> R.string.snygg__rule_element__key
|
||||
FlorisImeUi.KeyHint -> R.string.snygg__rule_element__key_hint
|
||||
FlorisImeUi.KeyPopup -> R.string.snygg__rule_element__key_popup
|
||||
FlorisImeUi.ClipboardHeader -> R.string.snygg__rule_element__clipboard_header
|
||||
FlorisImeUi.ClipboardItem -> R.string.snygg__rule_element__clipboard_item
|
||||
FlorisImeUi.ClipboardItemPopup -> R.string.snygg__rule_element__clipboard_item_popup
|
||||
FlorisImeUi.EmojiKey -> R.string.snygg__rule_element__emoji_key
|
||||
FlorisImeUi.EmojiKeyPopup -> R.string.snygg__rule_element__emoji_key_popup
|
||||
FlorisImeUi.EmojiTab -> R.string.snygg__rule_element__emoji_key_tab
|
||||
FlorisImeUi.ExtractedLandscapeInputLayout -> R.string.snygg__rule_element__extracted_landscape_input_layout
|
||||
FlorisImeUi.ExtractedLandscapeInputField -> R.string.snygg__rule_element__extracted_landscape_input_field
|
||||
FlorisImeUi.ExtractedLandscapeInputAction -> R.string.snygg__rule_element__extracted_landscape_input_action
|
||||
FlorisImeUi.GlideTrail -> R.string.snygg__rule_element__glide_trail
|
||||
FlorisImeUi.IncognitoModeIndicator -> R.string.snygg__rule_element__incognito_mode_indicator
|
||||
FlorisImeUi.OneHandedPanel -> R.string.snygg__rule_element__one_handed_panel
|
||||
FlorisImeUi.Smartbar -> R.string.snygg__rule_element__smartbar
|
||||
FlorisImeUi.SmartbarSharedActionsRow -> R.string.snygg__rule_element__smartbar_shared_actions_row
|
||||
FlorisImeUi.SmartbarSharedActionsToggle -> R.string.snygg__rule_element__smartbar_shared_actions_toggle
|
||||
FlorisImeUi.SmartbarExtendedActionsRow -> R.string.snygg__rule_element__smartbar_extended_actions_row
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle -> R.string.snygg__rule_element__smartbar_extended_actions_toggle
|
||||
FlorisImeUi.SmartbarActionKey -> R.string.snygg__rule_element__smartbar_action_key
|
||||
FlorisImeUi.SmartbarActionTile -> R.string.snygg__rule_element__smartbar_action_tile
|
||||
FlorisImeUi.SmartbarActionsOverflow -> R.string.snygg__rule_element__smartbar_actions_overflow
|
||||
FlorisImeUi.SmartbarActionsOverflowCustomizeButton -> R.string.snygg__rule_element__smartbar_actions_overflow_customize_button
|
||||
FlorisImeUi.SmartbarActionsEditor -> R.string.snygg__rule_element__smartbar_actions_editor
|
||||
FlorisImeUi.SmartbarActionsEditorHeader -> R.string.snygg__rule_element__smartbar_actions_editor_header
|
||||
FlorisImeUi.SmartbarActionsEditorSubheader -> R.string.snygg__rule_element__smartbar_actions_editor_subheader
|
||||
FlorisImeUi.SmartbarCandidatesRow -> R.string.snygg__rule_element__smartbar_candidates_row
|
||||
FlorisImeUi.SmartbarCandidateWord -> R.string.snygg__rule_element__smartbar_candidate_word
|
||||
FlorisImeUi.SmartbarCandidateClip -> R.string.snygg__rule_element__smartbar_candidate_clip
|
||||
FlorisImeUi.SmartbarCandidateSpacer -> R.string.snygg__rule_element__smartbar_candidate_spacer
|
||||
FlorisImeUi.SystemNavBar -> R.string.snygg__rule_element__system_nav_bar
|
||||
else -> null
|
||||
}
|
||||
}.let { if (it != null) { stringRes(it) } else { null } }
|
||||
}
|
||||
private val PropertyNameMap = mapOf(
|
||||
Snygg.Background to R.string.snygg__property_name__background,
|
||||
Snygg.Foreground to R.string.snygg__property_name__foreground,
|
||||
Snygg.BackgroundImage to R.string.snygg__property_name__background_image,
|
||||
Snygg.ContentScale to R.string.snygg__property_name__content_scale,
|
||||
Snygg.BorderColor to R.string.snygg__property_name__border_color,
|
||||
Snygg.BorderStyle to R.string.snygg__property_name__border_style,
|
||||
Snygg.BorderWidth to R.string.snygg__property_name__border_width,
|
||||
Snygg.FontFamily to R.string.snygg__property_name__font_family,
|
||||
Snygg.FontSize to R.string.snygg__property_name__font_size,
|
||||
Snygg.FontStyle to R.string.snygg__property_name__font_style,
|
||||
Snygg.FontWeight to R.string.snygg__property_name__font_weight,
|
||||
Snygg.LetterSpacing to R.string.snygg__property_name__letter_spacing,
|
||||
Snygg.LineHeight to R.string.snygg__property_name__line_height,
|
||||
Snygg.Margin to R.string.snygg__property_name__margin,
|
||||
Snygg.Padding to R.string.snygg__property_name__padding,
|
||||
Snygg.ShadowColor to R.string.snygg__property_name__shadow_color,
|
||||
Snygg.ShadowElevation to R.string.snygg__property_name__shadow_elevation,
|
||||
Snygg.Shape to R.string.snygg__property_name__shape,
|
||||
Snygg.Clip to R.string.snygg__property_name__clip,
|
||||
Snygg.Src to R.string.snygg__property_name__src,
|
||||
Snygg.TextAlign to R.string.snygg__property_name__text_align,
|
||||
Snygg.TextDecorationLine to R.string.snygg__property_name__text_decoration_line,
|
||||
Snygg.TextMaxLines to R.string.snygg__property_name__text_max_lines,
|
||||
Snygg.TextOverflow to R.string.snygg__property_name__text_overflow,
|
||||
"--primary" to R.string.snygg__property_name__var_primary,
|
||||
"--primary-variant" to R.string.snygg__property_name__var_primary_variant,
|
||||
"--secondary" to R.string.snygg__property_name__var_secondary,
|
||||
"--secondary-variant" to R.string.snygg__property_name__var_secondary_variant,
|
||||
"--background" to R.string.snygg__property_name__var_background,
|
||||
"--surface" to R.string.snygg__property_name__var_surface,
|
||||
"--surface-variant" to R.string.snygg__property_name__var_surface_variant,
|
||||
"--on-primary" to R.string.snygg__property_name__var_on_primary,
|
||||
"--on-secondary" to R.string.snygg__property_name__var_on_secondary,
|
||||
"--on-background" to R.string.snygg__property_name__var_on_background,
|
||||
"--on-surface" to R.string.snygg__property_name__var_on_surface,
|
||||
"--on-surface-variant" to R.string.snygg__property_name__var_on_surface_variant,
|
||||
"--shape" to R.string.snygg__property_name__var_shape,
|
||||
"--shape-variant" to R.string.snygg__property_name__var_shape_variant
|
||||
)
|
||||
|
||||
@Composable
|
||||
internal fun translatePropertyName(propertyName: String, level: SnyggLevel): String {
|
||||
internal fun Context.translatePropertyName(propertyName: String, level: SnyggLevel): String {
|
||||
return when (level) {
|
||||
SnyggLevel.DEVELOPER -> null
|
||||
else -> when (propertyName) {
|
||||
Snygg.Width -> R.string.snygg__property_name__width
|
||||
Snygg.Height -> R.string.snygg__property_name__height
|
||||
Snygg.Background -> R.string.snygg__property_name__background
|
||||
Snygg.Foreground -> R.string.snygg__property_name__foreground
|
||||
Snygg.BorderColor -> R.string.snygg__property_name__border_color
|
||||
Snygg.BorderStyle -> R.string.snygg__property_name__border_style
|
||||
Snygg.BorderWidth -> R.string.snygg__property_name__border_width
|
||||
Snygg.FontFamily -> R.string.snygg__property_name__font_family
|
||||
Snygg.FontSize -> R.string.snygg__property_name__font_size
|
||||
Snygg.FontStyle -> R.string.snygg__property_name__font_style
|
||||
Snygg.FontVariant -> R.string.snygg__property_name__font_variant
|
||||
Snygg.FontWeight -> R.string.snygg__property_name__font_weight
|
||||
Snygg.ShadowElevation -> R.string.snygg__property_name__shadow_elevation
|
||||
Snygg.Shape -> R.string.snygg__property_name__shape
|
||||
"--primary" -> R.string.snygg__property_name__var_primary
|
||||
"--primary-variant" -> R.string.snygg__property_name__var_primary_variant
|
||||
"--secondary" -> R.string.snygg__property_name__var_secondary
|
||||
"--secondary-variant" -> R.string.snygg__property_name__var_secondary_variant
|
||||
"--background" -> R.string.snygg__property_name__var_background
|
||||
"--surface" -> R.string.snygg__property_name__var_surface
|
||||
"--surface-variant" -> R.string.snygg__property_name__var_surface_variant
|
||||
"--on-primary" -> R.string.snygg__property_name__var_on_primary
|
||||
"--on-secondary" -> R.string.snygg__property_name__var_on_secondary
|
||||
"--on-background" -> R.string.snygg__property_name__var_on_background
|
||||
"--on-surface" -> R.string.snygg__property_name__var_on_surface
|
||||
"--on-surface-variant" -> R.string.snygg__property_name__var_on_surface_variant
|
||||
"--shape" -> R.string.snygg__property_name__var_shape
|
||||
"--shape-variant" -> R.string.snygg__property_name__var_shape_variant
|
||||
else -> null
|
||||
}
|
||||
else -> PropertyNameMap[propertyName]
|
||||
}.let { resId ->
|
||||
when {
|
||||
resId != null -> {
|
||||
stringRes(resId)
|
||||
getString(resId)
|
||||
}
|
||||
propertyName.isBlank() -> {
|
||||
stringRes(R.string.general__select_dropdown_value_placeholder)
|
||||
getString(R.string.general__select_dropdown_value_placeholder)
|
||||
}
|
||||
else -> {
|
||||
propertyName
|
||||
@@ -152,15 +126,14 @@ internal fun translatePropertyName(propertyName: String, level: SnyggLevel): Str
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun translatePropertyValue(
|
||||
internal fun Context.translatePropertyValue(
|
||||
propertyValue: SnyggValue,
|
||||
level: SnyggLevel,
|
||||
displayColorsAs: DisplayColorsAs,
|
||||
colorRepresentation: ColorRepresentation,
|
||||
): String {
|
||||
return when (propertyValue) {
|
||||
is SnyggSolidColorValue -> remember(propertyValue.color, displayColorsAs) {
|
||||
buildColorString(propertyValue.color, displayColorsAs)
|
||||
is SnyggStaticColorValue -> {
|
||||
colorRepresentation.formatColor(propertyValue.color, withAlpha = true)
|
||||
}
|
||||
else -> when (level) {
|
||||
SnyggLevel.DEVELOPER -> null
|
||||
@@ -176,51 +149,38 @@ internal fun translatePropertyValue(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun buildColorString(color: Color, displayColorsAs: DisplayColorsAs): String {
|
||||
return when (displayColorsAs) {
|
||||
DisplayColorsAs.HEX8 -> buildString {
|
||||
append(UnicodeCtrlChar.LeftToRightIsolate)
|
||||
append("#")
|
||||
append((color.red * RgbaColor.RedMax).roundToInt().toString(16).padStart(2, '0'))
|
||||
append((color.green * RgbaColor.GreenMax).roundToInt().toString(16).padStart(2, '0'))
|
||||
append((color.blue * RgbaColor.BlueMax).roundToInt().toString(16).padStart(2, '0'))
|
||||
append((color.alpha * 0xFF).roundToInt().toString(16).padStart(2, '0'))
|
||||
append(UnicodeCtrlChar.PopDirectionalIsolate)
|
||||
}
|
||||
DisplayColorsAs.RGBA -> buildString {
|
||||
append(UnicodeCtrlChar.LeftToRightIsolate)
|
||||
append("rgba(")
|
||||
append((color.red * RgbaColor.RedMax).roundToInt())
|
||||
append(",")
|
||||
append((color.green * RgbaColor.GreenMax).roundToInt())
|
||||
append(",")
|
||||
append((color.blue * RgbaColor.BlueMax).roundToInt())
|
||||
append(",")
|
||||
append(color.alpha)
|
||||
append(")")
|
||||
append(UnicodeCtrlChar.PopDirectionalIsolate)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val PropertyValueEncoderNameMap = mapOf(
|
||||
SnyggUndefinedValue to R.string.general__select_dropdown_value_placeholder,
|
||||
SnyggInheritValue to R.string.snygg__property_value__explicit_inherit,
|
||||
SnyggDefinedVarValue to R.string.snygg__property_value__defined_var,
|
||||
SnyggYesValue to R.string.snygg__property_value__yes,
|
||||
SnyggNoValue to R.string.snygg__property_value__no,
|
||||
SnyggStaticColorValue to R.string.snygg__property_value__solid_color,
|
||||
SnyggDynamicLightColorValue to R.string.snygg__property_value__material_you_light_color,
|
||||
SnyggDynamicDarkColorValue to R.string.snygg__property_value__material_you_dark_color,
|
||||
SnyggGenericFontFamilyValue to R.string.snygg__property_value__font_family_generic,
|
||||
SnyggCustomFontFamilyValue to R.string.snygg__property_value__font_family_custom,
|
||||
SnyggFontStyleValue to R.string.snygg__property_value__font_style,
|
||||
SnyggFontWeightValue to R.string.snygg__property_value__font_weight,
|
||||
SnyggPaddingValue to R.string.snygg__property_value__padding,
|
||||
SnyggRectangleShapeValue to R.string.snygg__property_value__rectangle_shape,
|
||||
SnyggCircleShapeValue to R.string.snygg__property_value__circle_shape,
|
||||
SnyggCutCornerDpShapeValue to R.string.snygg__property_value__cut_corner_shape_dp,
|
||||
SnyggCutCornerPercentShapeValue to R.string.snygg__property_value__cut_corner_shape_percent,
|
||||
SnyggRoundedCornerDpShapeValue to R.string.snygg__property_value__rounded_corner_shape_dp,
|
||||
SnyggRoundedCornerPercentShapeValue to R.string.snygg__property_value__rounded_corner_shape_percent,
|
||||
SnyggDpSizeValue to R.string.snygg__property_value__dp_size,
|
||||
SnyggSpSizeValue to R.string.snygg__property_value__sp_size,
|
||||
SnyggPercentageSizeValue to R.string.snygg__property_value__percentage_size,
|
||||
SnyggContentScaleValue to R.string.snygg__property_value__content_scale,
|
||||
SnyggTextAlignValue to R.string.snygg__property_value__text_align,
|
||||
SnyggTextDecorationLineValue to R.string.snygg__property_value__text_decoration_line,
|
||||
SnyggTextMaxLinesValue to R.string.snygg__property_value__text_max_lines,
|
||||
SnyggTextOverflowValue to R.string.snygg__property_value__text_overflow,
|
||||
SnyggUriValue to R.string.snygg__property_value__uri,
|
||||
)
|
||||
|
||||
@Composable
|
||||
internal fun translatePropertyValueEncoderName(encoder: SnyggValueEncoder): String {
|
||||
return when (encoder) {
|
||||
SnyggImplicitInheritValue -> R.string.general__select_dropdown_value_placeholder
|
||||
SnyggExplicitInheritValue -> R.string.snygg__property_value__explicit_inherit
|
||||
SnyggSolidColorValue -> R.string.snygg__property_value__solid_color
|
||||
SnyggMaterialYouLightColorValue -> R.string.snygg__property_value__material_you_light_color
|
||||
SnyggMaterialYouDarkColorValue -> R.string.snygg__property_value__material_you_dark_color
|
||||
SnyggRectangleShapeValue -> R.string.snygg__property_value__rectangle_shape
|
||||
SnyggCircleShapeValue -> R.string.snygg__property_value__circle_shape
|
||||
SnyggCutCornerDpShapeValue -> R.string.snygg__property_value__cut_corner_shape_dp
|
||||
SnyggCutCornerPercentShapeValue -> R.string.snygg__property_value__cut_corner_shape_percent
|
||||
SnyggRoundedCornerDpShapeValue -> R.string.snygg__property_value__rounded_corner_shape_dp
|
||||
SnyggRoundedCornerPercentShapeValue -> R.string.snygg__property_value__rounded_corner_shape_percent
|
||||
SnyggDpSizeValue -> R.string.snygg__property_value__dp_size
|
||||
SnyggSpSizeValue -> R.string.snygg__property_value__sp_size
|
||||
SnyggPercentageSizeValue -> R.string.snygg__property_value__percentage_size
|
||||
SnyggDefinedVarValue -> R.string.snygg__property_value__defined_var
|
||||
else -> null
|
||||
}.let { if (it != null) { stringRes(it) } else { encoder::class.simpleName ?: "" } }.toString()
|
||||
internal fun Context.translatePropertyValueEncoderName(encoder: SnyggValueEncoder): String {
|
||||
return PropertyValueEncoderNameMap[encoder]?.let { getString(it) }
|
||||
?: encoder::class.simpleNameOrEnclosing().orEmpty()
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisErrorCard
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisHyperlinkText
|
||||
@@ -47,6 +48,7 @@ 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.vectorResource
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
|
||||
@OptIn(ExperimentalJetPrefDatastoreUi::class)
|
||||
@@ -79,28 +81,18 @@ fun TypingScreen() = FlorisScreen {
|
||||
summary = stringRes(R.string.pref__suggestion__block_possibly_offensive__summary),
|
||||
enabledIf = { prefs.suggestion.enabled isEqualTo true },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.suggestion.clipboardContentEnabled,
|
||||
title = stringRes(R.string.pref__suggestion__clipboard_content_enabled__label),
|
||||
summary = stringRes(R.string.pref__suggestion__clipboard_content_enabled__summary),
|
||||
enabledIf = { prefs.suggestion.enabled isEqualTo true },
|
||||
)
|
||||
DialogSliderPreference(
|
||||
prefs.suggestion.clipboardContentTimeout,
|
||||
title = stringRes(R.string.pref__suggestion__clipboard_content_timeout__label),
|
||||
valueLabel = { stringRes(R.string.pref__suggestion__clipboard_content_timeout__summary, "v" to it) },
|
||||
min = 30,
|
||||
max = 300,
|
||||
stepIncrement = 5,
|
||||
enabledIf = { prefs.suggestion.enabled isEqualTo true },
|
||||
visibleIf = { prefs.suggestion.clipboardContentEnabled isEqualTo true },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.suggestion.api30InlineSuggestionsEnabled,
|
||||
title = stringRes(R.string.pref__suggestion__api30_inline_suggestions_enabled__label),
|
||||
summary = stringRes(R.string.pref__suggestion__api30_inline_suggestions_enabled__summary),
|
||||
visibleIf = { AndroidVersion.ATLEAST_API30_R },
|
||||
)
|
||||
ListPreference(
|
||||
prefs.suggestion.incognitoMode,
|
||||
icon = vectorResource(id = R.drawable.ic_incognito),
|
||||
title = stringRes(R.string.pref__suggestion__incognito_mode__label),
|
||||
entries = enumDisplayEntriesOf(IncognitoMode::class),
|
||||
)
|
||||
}
|
||||
|
||||
PreferenceGroup(title = stringRes(R.string.pref__correction__title)) {
|
||||
|
||||
@@ -31,20 +31,16 @@ import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
@@ -54,9 +50,7 @@ import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.ToggleOff
|
||||
import androidx.compose.material.icons.filled.ToggleOn
|
||||
import androidx.compose.material.icons.filled.Videocam
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -73,12 +67,6 @@ import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDirection
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
@@ -90,16 +78,12 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.media.KeyboardLikeButton
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButtonWithInnerPadding
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisStaggeredVerticalGrid
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisTextButton
|
||||
import dev.patrickgold.florisboard.lib.compose.autoMirrorForRtl
|
||||
import dev.patrickgold.florisboard.lib.compose.florisVerticalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.rippleClickable
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.lib.util.NetworkUtils
|
||||
@@ -108,20 +92,14 @@ import org.florisboard.lib.android.AndroidKeyguardManager
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.systemService
|
||||
import org.florisboard.lib.snygg.SnyggPropertySet
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.snyggBorder
|
||||
import org.florisboard.lib.snygg.ui.snyggClip
|
||||
import org.florisboard.lib.snygg.ui.snyggShadow
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggIconButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
private val ContentPadding = PaddingValues(horizontal = 4.dp)
|
||||
private val ItemMargin = PaddingValues(all = 6.dp)
|
||||
private val ItemPadding = PaddingValues(vertical = 8.dp, horizontal = 12.dp)
|
||||
private val DescriptionPadding = PaddingValues(top = 4.dp, start = 12.dp, end = 12.dp)
|
||||
private val ItemWidth = 200.dp
|
||||
private val DialogWidth = 240.dp
|
||||
|
||||
@@ -139,69 +117,79 @@ fun ClipboardInputLayout(
|
||||
val historyEnabled by prefs.clipboard.historyEnabled.observeAsState()
|
||||
val history by clipboardManager.history.observeAsNonNullState()
|
||||
|
||||
val innerHeight = FlorisImeSizing.imeUiHeight() - FlorisImeSizing.smartbarHeight
|
||||
var popupItem by remember(history) { mutableStateOf<ClipboardItem?>(null) }
|
||||
var showClearAllHistory by remember { mutableStateOf(false) }
|
||||
|
||||
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardHeader)
|
||||
val itemStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardItem)
|
||||
val popupStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardItemPopup)
|
||||
val enableHistoryButtonStyle = FlorisImeTheme.style.get(FlorisImeUi.ClipboardEnableHistoryButton)
|
||||
|
||||
fun isPopupSurfaceActive() = popupItem != null || showClearAllHistory
|
||||
|
||||
@Composable
|
||||
fun HeaderRow() {
|
||||
Row(
|
||||
SnyggRow(FlorisImeUi.ClipboardHeader.elementName,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.smartbarHeight)
|
||||
.snyggBackground(context, headerStyle),
|
||||
.height(FlorisImeSizing.smartbarHeight),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
FlorisIconButtonWithInnerPadding(
|
||||
val sizeModifier = Modifier
|
||||
.sizeIn(maxHeight = FlorisImeSizing.smartbarHeight)
|
||||
.aspectRatio(1f)
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.ClipboardHeaderButton.elementName,
|
||||
onClick = { keyboardManager.activeState.imeUiMode = ImeUiMode.TEXT },
|
||||
icon = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
iconColor = headerStyle.foreground.solidColor(context),
|
||||
)
|
||||
Text(
|
||||
modifier = sizeModifier,
|
||||
) {
|
||||
SnyggIcon(
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
)
|
||||
}
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.ClipboardHeaderText.elementName,
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringRes(R.string.clipboard__header_title),
|
||||
color = headerStyle.foreground.solidColor(context),
|
||||
fontSize = headerStyle.fontSize.spSize(),
|
||||
)
|
||||
FlorisIconButtonWithInnerPadding(
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.ClipboardHeaderButton.elementName,
|
||||
onClick = { prefs.clipboard.historyEnabled.set(!historyEnabled) },
|
||||
modifier = Modifier.autoMirrorForRtl(),
|
||||
icon = if (historyEnabled) {
|
||||
Icons.Default.ToggleOn
|
||||
} else {
|
||||
Icons.Default.ToggleOff
|
||||
},
|
||||
iconColor = headerStyle.foreground.solidColor(context),
|
||||
modifier = sizeModifier.autoMirrorForRtl(),
|
||||
enabled = !deviceLocked && !isPopupSurfaceActive(),
|
||||
)
|
||||
FlorisIconButtonWithInnerPadding(
|
||||
) {
|
||||
SnyggIcon(
|
||||
imageVector = if (historyEnabled) {
|
||||
Icons.Default.ToggleOn
|
||||
} else {
|
||||
Icons.Default.ToggleOff
|
||||
},
|
||||
)
|
||||
}
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.ClipboardHeaderButton.elementName,
|
||||
onClick = { showClearAllHistory = true },
|
||||
modifier = Modifier.autoMirrorForRtl(),
|
||||
icon = Icons.Default.ClearAll,
|
||||
iconColor = headerStyle.foreground.solidColor(context),
|
||||
modifier = sizeModifier.autoMirrorForRtl(),
|
||||
enabled = !deviceLocked && historyEnabled && history.all.isNotEmpty() && !isPopupSurfaceActive(),
|
||||
)
|
||||
FlorisIconButtonWithInnerPadding(
|
||||
) {
|
||||
SnyggIcon(
|
||||
imageVector = Icons.Default.ClearAll,
|
||||
)
|
||||
}
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.ClipboardHeaderButton.elementName,
|
||||
onClick = {
|
||||
context.showShortToast("TODO: implement inline clip item editing")
|
||||
},
|
||||
icon = Icons.Default.Edit,
|
||||
iconColor = headerStyle.foreground.solidColor(context),
|
||||
modifier = sizeModifier,
|
||||
enabled = !deviceLocked && historyEnabled && !isPopupSurfaceActive(),
|
||||
)
|
||||
) {
|
||||
SnyggIcon(
|
||||
imageVector = Icons.Default.Edit,
|
||||
)
|
||||
}
|
||||
KeyboardLikeButton(
|
||||
modifier = sizeModifier,
|
||||
inputEventDispatcher = keyboardManager.inputEventDispatcher,
|
||||
keyData = TextKeyData.DELETE,
|
||||
element = FlorisImeUi.ClipboardHeader,
|
||||
elementName = FlorisImeUi.ClipboardHeaderButton.elementName,
|
||||
) {
|
||||
Icon(Icons.AutoMirrored.Outlined.Backspace, null)
|
||||
SnyggIcon(imageVector = Icons.AutoMirrored.Outlined.Backspace)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,17 +198,11 @@ fun ClipboardInputLayout(
|
||||
@Composable
|
||||
fun ClipItemView(
|
||||
item: ClipboardItem,
|
||||
style: SnyggPropertySet,
|
||||
contentScrollInsteadOfClip: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val fontSize = style.fontSize.spSize() safeTimes 1f
|
||||
SnyggSurface(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(ItemMargin),
|
||||
style = style,
|
||||
clip = true,
|
||||
SnyggBox(FlorisImeUi.ClipboardItem.elementName,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
clickAndSemanticsModifier = Modifier.combinedClickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = ripple(),
|
||||
@@ -252,14 +234,9 @@ fun ClipboardInputLayout(
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(ItemPadding),
|
||||
SnyggText(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = bitmap.exceptionOrNull()?.message ?: "Unknown error",
|
||||
style = TextStyle(textDirection = TextDirection.Ltr),
|
||||
color = Color.Red,
|
||||
fontSize = fontSize,
|
||||
)
|
||||
}
|
||||
} else if (item.type == ItemType.VIDEO) {
|
||||
@@ -299,31 +276,20 @@ fun ClipboardInputLayout(
|
||||
tint = Color.Black,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(ItemPadding),
|
||||
SnyggText(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = bitmap.exceptionOrNull()?.message ?: "Unknown error",
|
||||
style = TextStyle(textDirection = TextDirection.Ltr),
|
||||
color = Color.Red,
|
||||
fontSize = fontSize,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val text = item.stringRepresentation()
|
||||
Column {
|
||||
ClipTextItemDescription(text, style)
|
||||
Text(
|
||||
ClipTextItemDescription(text)
|
||||
SnyggText(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.run { if (contentScrollInsteadOfClip) this.florisVerticalScroll() else this }
|
||||
.padding(ItemPadding),
|
||||
.run { if (contentScrollInsteadOfClip) this.florisVerticalScroll() else this },
|
||||
text = item.displayText(),
|
||||
style = TextStyle(textDirection = TextDirection.ContentOrLtr),
|
||||
color = style.foreground.solidColor(context),
|
||||
fontSize = style.fontSize.spSize(),
|
||||
maxLines = if (contentScrollInsteadOfClip) Int.MAX_VALUE else 5,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -332,15 +298,12 @@ fun ClipboardInputLayout(
|
||||
|
||||
@Composable
|
||||
fun HistoryMainView() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(innerHeight),
|
||||
SnyggBox(FlorisImeUi.ClipboardContent.elementName,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
val historyAlpha by animateFloatAsState(targetValue = if (isPopupSurfaceActive()) 0.12f else 1f)
|
||||
Column(
|
||||
SnyggColumn(
|
||||
modifier = Modifier
|
||||
.padding(ContentPadding)
|
||||
.fillMaxSize()
|
||||
.alpha(historyAlpha)
|
||||
.florisVerticalScroll(),
|
||||
@@ -348,42 +311,38 @@ fun ClipboardInputLayout(
|
||||
if (history.pinned.isNotEmpty()) {
|
||||
ClipCategoryTitle(
|
||||
text = stringRes(R.string.clipboard__group_pinned),
|
||||
style = itemStyle,
|
||||
)
|
||||
FlorisStaggeredVerticalGrid(maxColumnWidth = ItemWidth) {
|
||||
for (item in history.pinned) {
|
||||
ClipItemView(item, itemStyle, contentScrollInsteadOfClip = false)
|
||||
ClipItemView(item, contentScrollInsteadOfClip = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (history.recent.isNotEmpty()) {
|
||||
ClipCategoryTitle(
|
||||
text = stringRes(R.string.clipboard__group_recent),
|
||||
style = itemStyle,
|
||||
)
|
||||
FlorisStaggeredVerticalGrid(maxColumnWidth = ItemWidth) {
|
||||
for (item in history.recent) {
|
||||
ClipItemView(item, itemStyle, contentScrollInsteadOfClip = false)
|
||||
ClipItemView(item, contentScrollInsteadOfClip = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (history.other.isNotEmpty()) {
|
||||
ClipCategoryTitle(
|
||||
text = stringRes(R.string.clipboard__group_other),
|
||||
style = itemStyle,
|
||||
)
|
||||
FlorisStaggeredVerticalGrid(maxColumnWidth = ItemWidth) {
|
||||
for (item in history.other) {
|
||||
ClipItemView(item, itemStyle, contentScrollInsteadOfClip = false)
|
||||
ClipItemView(item, contentScrollInsteadOfClip = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (popupItem != null) {
|
||||
Row(
|
||||
SnyggRow(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(ContentPadding)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures { popupItem = null }
|
||||
},
|
||||
@@ -393,17 +352,9 @@ fun ClipboardInputLayout(
|
||||
ClipItemView(
|
||||
modifier = Modifier.widthIn(max = ItemWidth),
|
||||
item = popupItem!!,
|
||||
style = itemStyle,
|
||||
contentScrollInsteadOfClip = true,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(ItemMargin)
|
||||
.snyggShadow(popupStyle)
|
||||
.snyggBorder(context, popupStyle)
|
||||
.snyggBackground(context, popupStyle)
|
||||
.snyggClip(popupStyle),
|
||||
) {
|
||||
SnyggColumn(FlorisImeUi.ClipboardItemPopup.elementName) {
|
||||
PopupAction(
|
||||
iconId = R.drawable.ic_pin,
|
||||
text = stringRes(if (popupItem!!.isPinned) {
|
||||
@@ -411,7 +362,6 @@ fun ClipboardInputLayout(
|
||||
} else {
|
||||
R.string.clip__pin_item
|
||||
}),
|
||||
style = popupStyle,
|
||||
) {
|
||||
if (popupItem!!.isPinned) {
|
||||
clipboardManager.unpinClip(popupItem!!)
|
||||
@@ -423,7 +373,6 @@ fun ClipboardInputLayout(
|
||||
PopupAction(
|
||||
iconId = R.drawable.ic_delete,
|
||||
text = stringRes(R.string.clip__delete_item),
|
||||
style = popupStyle,
|
||||
) {
|
||||
clipboardManager.deleteClip(popupItem!!)
|
||||
popupItem = null
|
||||
@@ -431,7 +380,6 @@ fun ClipboardInputLayout(
|
||||
PopupAction(
|
||||
iconId = R.drawable.ic_content_paste,
|
||||
text = stringRes(R.string.clip__paste_item),
|
||||
style = popupStyle,
|
||||
) {
|
||||
clipboardManager.pasteItem(popupItem!!)
|
||||
popupItem = null
|
||||
@@ -440,51 +388,53 @@ fun ClipboardInputLayout(
|
||||
}
|
||||
}
|
||||
if (showClearAllHistory) {
|
||||
Row(
|
||||
SnyggRow(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(ContentPadding)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures { showClearAllHistory = false }
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceAround,
|
||||
) {
|
||||
Column(
|
||||
SnyggColumn(
|
||||
elementName = FlorisImeUi.ClipboardClearAllDialog.elementName,
|
||||
modifier = Modifier
|
||||
.width(DialogWidth)
|
||||
.snyggShadow(popupStyle)
|
||||
.snyggBorder(context, popupStyle)
|
||||
.snyggBackground(context, popupStyle)
|
||||
.snyggClip(popupStyle)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures { /* Do nothing */ }
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.ClipboardClearAllDialogMessage.elementName,
|
||||
text = stringRes(R.string.clipboard__confirm_clear_history__message),
|
||||
color = popupStyle.foreground.solidColor(context),
|
||||
)
|
||||
Row(modifier = Modifier.padding(horizontal = 8.dp)) {
|
||||
SnyggRow(FlorisImeUi.ClipboardClearAllDialogButtons.elementName) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
FlorisTextButton(
|
||||
SnyggButton(
|
||||
elementName = FlorisImeUi.ClipboardClearAllDialogButton.elementName,
|
||||
attributes = mapOf("action" to "no"),
|
||||
onClick = {
|
||||
showClearAllHistory = false
|
||||
},
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
text = stringRes(R.string.action__no),
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = popupStyle.foreground.solidColor(context)),
|
||||
)
|
||||
FlorisTextButton(
|
||||
) {
|
||||
SnyggText(
|
||||
text = stringRes(R.string.action__no),
|
||||
)
|
||||
}
|
||||
SnyggButton(
|
||||
elementName = FlorisImeUi.ClipboardClearAllDialogButton.elementName,
|
||||
attributes = mapOf("action" to "yes"),
|
||||
onClick = {
|
||||
clipboardManager.clearHistory()
|
||||
context.showShortToast(R.string.clipboard__cleared_history)
|
||||
showClearAllHistory = false
|
||||
},
|
||||
text = stringRes(R.string.action__yes),
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = popupStyle.foreground.solidColor(context)),
|
||||
)
|
||||
) {
|
||||
SnyggText(
|
||||
text = stringRes(R.string.action__yes),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,98 +444,62 @@ fun ClipboardInputLayout(
|
||||
|
||||
@Composable
|
||||
fun HistoryEmptyView() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(innerHeight)
|
||||
.padding(ContentPadding),
|
||||
SnyggColumn(FlorisImeUi.ClipboardContent.elementName,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 24.dp, bottom = 8.dp),
|
||||
SnyggText(
|
||||
text = stringRes(R.string.clipboard__empty__title),
|
||||
color = itemStyle.foreground.solidColor(context),
|
||||
fontSize = itemStyle.fontSize.spSize() safeTimes 1.1f,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Text(
|
||||
SnyggText(
|
||||
text = stringRes(R.string.clipboard__empty__message),
|
||||
color = itemStyle.foreground.solidColor(context),
|
||||
fontSize = itemStyle.fontSize.spSize() safeTimes 1f,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistoryDisabledView() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(innerHeight)
|
||||
.padding(ContentPadding),
|
||||
contentAlignment = Alignment.TopCenter,
|
||||
SnyggColumn(FlorisImeUi.ClipboardContent.elementName,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
SnyggSurface(
|
||||
modifier = Modifier
|
||||
.padding(ItemMargin)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
style = itemStyle,
|
||||
contentPadding = ItemPadding,
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.ClipboardHistoryDisabledTitle.elementName,
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
text = stringRes(R.string.clipboard__disabled__title),
|
||||
)
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.ClipboardHistoryDisabledMessage.elementName,
|
||||
text = stringRes(R.string.clipboard__disabled__message),
|
||||
)
|
||||
SnyggButton(FlorisImeUi.ClipboardHistoryDisabledButton.elementName,
|
||||
onClick = { prefs.clipboard.historyEnabled.set(true) },
|
||||
modifier = Modifier.align(Alignment.End),
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
text = stringRes(R.string.clipboard__disabled__title),
|
||||
color = itemStyle.foreground.solidColor(context),
|
||||
fontSize = itemStyle.fontSize.spSize() safeTimes 1.1f,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Text(
|
||||
text = stringRes(R.string.clipboard__disabled__message),
|
||||
color = itemStyle.foreground.solidColor(context),
|
||||
fontSize = itemStyle.fontSize.spSize() safeTimes 1f,
|
||||
)
|
||||
SnyggButton(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
.align(Alignment.End),
|
||||
onClick = { prefs.clipboard.historyEnabled.set(true) },
|
||||
style = enableHistoryButtonStyle,
|
||||
text = stringRes(R.string.clipboard__disabled__enable_button)
|
||||
)
|
||||
}
|
||||
SnyggText(
|
||||
text = stringRes(R.string.clipboard__disabled__enable_button),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistoryLockedView() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(innerHeight)
|
||||
.padding(ContentPadding),
|
||||
SnyggColumn(FlorisImeUi.ClipboardContent.elementName,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 24.dp, bottom = 8.dp),
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.ClipboardHistoryLockedTitle.elementName,
|
||||
text = stringRes(R.string.clipboard__locked__title),
|
||||
color = itemStyle.foreground.solidColor(context),
|
||||
fontSize = itemStyle.fontSize.spSize() safeTimes 1.1f,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Text(
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.ClipboardHistoryLockedMessage.elementName,
|
||||
text = stringRes(R.string.clipboard__locked__message),
|
||||
color = itemStyle.foreground.solidColor(context),
|
||||
fontSize = itemStyle.fontSize.spSize() safeTimes 1f,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
SnyggColumn(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.imeUiHeight()),
|
||||
@@ -610,29 +524,19 @@ fun ClipboardInputLayout(
|
||||
@Composable
|
||||
private fun ClipCategoryTitle(
|
||||
text: String,
|
||||
style: SnyggPropertySet,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
modifier = modifier
|
||||
.padding(ItemMargin)
|
||||
.padding(top = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
SnyggText(FlorisImeUi.ClipboardSubheader.elementName,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
text = text.uppercase(),
|
||||
color = style.foreground.solidColor(context),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = style.fontSize.spSize() safeTimes 0.8f,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ClipTextItemDescription(
|
||||
text: String,
|
||||
style: SnyggPropertySet,
|
||||
modifier: Modifier = Modifier,
|
||||
): Unit = with(LocalDensity.current) {
|
||||
val context = LocalContext.current
|
||||
val iconId: Int?
|
||||
val description: String?
|
||||
when {
|
||||
@@ -654,27 +558,16 @@ private fun ClipTextItemDescription(
|
||||
}
|
||||
}
|
||||
if (iconId != null && description != null) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.padding(DescriptionPadding)
|
||||
.offset(y = DescriptionPadding.calculateTopPadding()),
|
||||
SnyggRow(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val fontSize = style.fontSize.spSize()
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp)
|
||||
.requiredSize(fontSize.toDp()),
|
||||
SnyggIcon(
|
||||
painter = painterResource(id = iconId),
|
||||
contentDescription = null,
|
||||
tint = style.foreground.solidColor(context),
|
||||
)
|
||||
Text(
|
||||
SnyggText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = description,
|
||||
color = style.foreground.solidColor(context),
|
||||
fontSize = fontSize safeTimes 0.8f,
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -684,29 +577,19 @@ private fun ClipTextItemDescription(
|
||||
private fun PopupAction(
|
||||
@DrawableRes iconId: Int,
|
||||
text: String,
|
||||
style: SnyggPropertySet,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Row(
|
||||
modifier = modifier
|
||||
.width(ItemWidth)
|
||||
.rippleClickable(onClick = onClick)
|
||||
.padding(all = 8.dp),
|
||||
SnyggRow(FlorisImeUi.ClipboardItemPopupAction.elementName,
|
||||
modifier = modifier.rippleClickable(onClick = onClick),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
SnyggIcon(FlorisImeUi.ClipboardItemPopupActionIcon.elementName,
|
||||
painter = painterResource(iconId),
|
||||
contentDescription = null,
|
||||
tint = style.foreground.solidColor(context),
|
||||
)
|
||||
Text(
|
||||
SnyggText(FlorisImeUi.ClipboardItemPopupActionText.elementName,
|
||||
modifier = Modifier.weight(1f),
|
||||
text = text,
|
||||
color = style.foreground.solidColor(context),
|
||||
fontSize = style.fontSize.spSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.isUnspecified
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -121,9 +120,8 @@ class FlorisCopyToClipboardActivity : ComponentActivity() {
|
||||
|
||||
setContent {
|
||||
ProvideLocalizedResources(this, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
val theme by prefs.advanced.settingsTheme.observeAsState()
|
||||
val accentColor by prefs.advanced.accentColor.observeAsState()
|
||||
FlorisAppTheme(theme, accentColor.isUnspecified) {
|
||||
val theme by prefs.other.settingsTheme.observeAsState()
|
||||
FlorisAppTheme(theme) {
|
||||
BottomSheet {
|
||||
Row {
|
||||
Text(
|
||||
|
||||
@@ -18,12 +18,8 @@ package dev.patrickgold.florisboard.ime.core
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
@@ -32,28 +28,23 @@ import androidx.compose.material.icons.filled.RadioButtonChecked
|
||||
import androidx.compose.material.icons.filled.RadioButtonUnchecked
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItemDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardState
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.rippleClickable
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefListItem
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.snyggClip
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
@Composable
|
||||
fun SelectSubtypePanel(modifier: Modifier = Modifier) {
|
||||
@@ -66,33 +57,17 @@ fun SelectSubtypePanel(modifier: Modifier = Modifier) {
|
||||
|
||||
val currentlySelected = subtypeManager.activeSubtype.id
|
||||
|
||||
val panelStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditor)
|
||||
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorHeader)
|
||||
val subheaderStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorSubheader)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.snyggBackground(context, panelStyle, fallbackColor = FlorisImeTheme.fallbackSurfaceColor())
|
||||
.snyggClip(panelStyle),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(48.dp)
|
||||
.snyggBackground(context, headerStyle),
|
||||
SnyggColumn(FlorisImeUi.SubtypePanel.elementName, modifier = modifier.safeDrawingPadding()) {
|
||||
SnyggRow(
|
||||
elementName = FlorisImeUi.SubtypePanelHeader.elementName,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
SnyggText(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
.clickable(false) {},
|
||||
text = stringRes(R.string.select_subtype_panel__header),
|
||||
color = headerStyle.foreground.solidColor(
|
||||
context,
|
||||
default = FlorisImeTheme.fallbackContentColor()
|
||||
),
|
||||
fontSize = headerStyle.fontSize.spSize(),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -121,22 +96,14 @@ fun SelectSubtypePanel(modifier: Modifier = Modifier) {
|
||||
}
|
||||
},
|
||||
text = it.primaryLocale.displayName(),
|
||||
colors = ListItemDefaults.colors(
|
||||
leadingIconColor = subheaderStyle.foreground.solidColor(context),
|
||||
headlineColor = subheaderStyle.foreground.solidColor(context),
|
||||
containerColor = subheaderStyle.background.solidColor(context),
|
||||
)
|
||||
colors = ListItemDefaults.colors(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(Modifier
|
||||
.systemBarsPadding()
|
||||
.snyggBackground(context, panelStyle))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun KeyboardState.isSubtypeSelectionShowing(): Boolean {
|
||||
return isSubtypeSelectionVisible
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ abstract class AbstractEditorInstance(context: Context) {
|
||||
abstract fun determineComposer(composerName: ExtensionComponentName): Composer
|
||||
|
||||
protected open fun shouldDetermineComposingRegion(editorInfo: FlorisEditorInfo): Boolean {
|
||||
return editorInfo.isRichInputEditor
|
||||
return editorInfo.isRichInputEditor && !editorInfo.inputAttributes.flagTextNoSuggestions
|
||||
}
|
||||
|
||||
private suspend fun determineLocalComposing(
|
||||
|
||||
@@ -119,11 +119,11 @@ class EditorInstance(context: Context) : AbstractEditorInstance(context) {
|
||||
//!instance.inputAttributes.flagTextAutoComplete &&
|
||||
//!instance.inputAttributes.flagTextNoSuggestions
|
||||
}
|
||||
activeState.isIncognitoMode = when (prefs.advanced.incognitoMode.get()) {
|
||||
activeState.isIncognitoMode = when (prefs.suggestion.incognitoMode.get()) {
|
||||
IncognitoMode.FORCE_OFF -> false
|
||||
IncognitoMode.FORCE_ON -> true
|
||||
IncognitoMode.DYNAMIC_ON_OFF -> {
|
||||
editorInfo.imeOptions.flagNoPersonalizedLearning || prefs.advanced.forceIncognitoModeFromDynamic.get()
|
||||
editorInfo.imeOptions.flagNoPersonalizedLearning || prefs.suggestion.forceIncognitoModeFromDynamic.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,5 +43,7 @@ enum class InputShiftState(val value: Int) {
|
||||
fun fromInt(int: Int) = entries.firstOrNull { it.value == int } ?: UNSHIFTED
|
||||
}
|
||||
|
||||
fun attrName() = name.lowercase()
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
|
||||
@@ -206,7 +206,8 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
|
||||
Icons.Default.DeleteSweep
|
||||
}
|
||||
KeyCode.COMPACT_LAYOUT_TO_LEFT,
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> {
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT,
|
||||
KeyCode.TOGGLE_COMPACT_LAYOUT -> {
|
||||
context()?.vectorResource(id = R.drawable.ic_accessibility_one_handed)
|
||||
}
|
||||
KeyCode.VOICE_INPUT -> {
|
||||
|
||||
@@ -119,7 +119,7 @@ fun ProvideKeyboardRowBaseHeight(content: @Composable () -> Unit) {
|
||||
|
||||
val heightFactorPortrait by prefs.keyboard.heightFactorPortrait.observeAsTransformingState { it.toFloat() / 100f }
|
||||
val heightFactorLandscape by prefs.keyboard.heightFactorLandscape.observeAsTransformingState { it.toFloat() / 100f }
|
||||
val oneHandedMode by prefs.keyboard.oneHandedMode.observeAsState()
|
||||
val oneHandedMode by prefs.keyboard.oneHandedModeEnabled.observeAsState()
|
||||
val oneHandedModeScaleFactor by prefs.keyboard.oneHandedModeScaleFactor.observeAsTransformingState { it.toFloat() / 100f }
|
||||
|
||||
// Only set systemBarHeights on api 35 or later because https://developer.android.com/about/versions/15/behavior-changes-15#stable-configuration
|
||||
@@ -134,7 +134,7 @@ fun ProvideKeyboardRowBaseHeight(content: @Composable () -> Unit) {
|
||||
) {
|
||||
calcInputViewHeight(resources, systemBarHeights) * when {
|
||||
configuration.isOrientationLandscape() -> heightFactorLandscape
|
||||
else -> heightFactorPortrait * (if (oneHandedMode != OneHandedMode.OFF) oneHandedModeScaleFactor else 1f)
|
||||
else -> heightFactorPortrait * (if (oneHandedMode) oneHandedModeScaleFactor else 1f)
|
||||
}
|
||||
}
|
||||
val smartbarHeight = baseRowHeight * 0.753f
|
||||
|
||||
@@ -236,11 +236,8 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
return subtypeManager.subtypes.size > 1
|
||||
}
|
||||
|
||||
fun toggleOneHandedMode(isRight: Boolean) {
|
||||
prefs.keyboard.oneHandedMode.set(when (prefs.keyboard.oneHandedMode.get()) {
|
||||
OneHandedMode.OFF -> if (isRight) { OneHandedMode.END } else { OneHandedMode.START }
|
||||
else -> OneHandedMode.OFF
|
||||
})
|
||||
fun toggleOneHandedMode() {
|
||||
prefs.keyboard.oneHandedModeEnabled.set(!prefs.keyboard.oneHandedModeEnabled.get())
|
||||
}
|
||||
|
||||
fun executeSwipeAction(swipeAction: SwipeAction) {
|
||||
@@ -583,7 +580,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
* Handles a [KeyCode.TOGGLE_INCOGNITO_MODE] event.
|
||||
*/
|
||||
private fun handleToggleIncognitoMode() {
|
||||
prefs.advanced.forceIncognitoModeFromDynamic.set(!prefs.advanced.forceIncognitoModeFromDynamic.get())
|
||||
prefs.suggestion.forceIncognitoModeFromDynamic.set(!prefs.suggestion.forceIncognitoModeFromDynamic.get())
|
||||
val newState = !activeState.isIncognitoMode
|
||||
activeState.isIncognitoMode = newState
|
||||
lastToastReference.get()?.cancel()
|
||||
@@ -720,8 +717,15 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
clipboardManager.updatePrimaryClip(null)
|
||||
appContext.showShortToast(R.string.clipboard__cleared_primary_clip)
|
||||
}
|
||||
KeyCode.COMPACT_LAYOUT_TO_LEFT -> toggleOneHandedMode(isRight = false)
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> toggleOneHandedMode(isRight = true)
|
||||
KeyCode.TOGGLE_COMPACT_LAYOUT -> toggleOneHandedMode()
|
||||
KeyCode.COMPACT_LAYOUT_TO_LEFT -> {
|
||||
prefs.keyboard.oneHandedMode.set(OneHandedMode.START)
|
||||
toggleOneHandedMode()
|
||||
}
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> {
|
||||
prefs.keyboard.oneHandedMode.set(OneHandedMode.END)
|
||||
toggleOneHandedMode()
|
||||
}
|
||||
KeyCode.DELETE -> handleDelete()
|
||||
KeyCode.DELETE_WORD -> handleDeleteWord()
|
||||
KeyCode.ENTER -> handleEnter()
|
||||
@@ -965,7 +969,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
KeyCode.CLIPBOARD_SELECT_ALL -> {
|
||||
editorInfo.isRichInputEditor
|
||||
}
|
||||
KeyCode.TOGGLE_INCOGNITO_MODE -> when (prefs.advanced.incognitoMode.get()) {
|
||||
KeyCode.TOGGLE_INCOGNITO_MODE -> when (prefs.suggestion.incognitoMode.get()) {
|
||||
IncognitoMode.FORCE_OFF, IncognitoMode.FORCE_ON -> false
|
||||
IncognitoMode.DYNAMIC_ON_OFF -> !editorInfo.imeOptions.flagNoPersonalizedLearning
|
||||
}
|
||||
|
||||
@@ -34,5 +34,7 @@ enum class KeyboardMode(val value: Int) {
|
||||
fun fromInt(int: Int) = entries.firstOrNull { it.value == int } ?: CHARACTERS
|
||||
}
|
||||
|
||||
fun attrName() = name.lowercase()
|
||||
|
||||
fun toInt() = value
|
||||
}
|
||||
|
||||
@@ -20,18 +20,19 @@ import android.annotation.SuppressLint
|
||||
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.indication
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.foundation.interaction.collectIsPressedAsState
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.Backspace
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -46,7 +47,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.ime.input.InputEventDispatcher
|
||||
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
@@ -54,10 +54,12 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiData
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiPaletteView
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import org.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
|
||||
@SuppressLint("MutableCollectionMutableState")
|
||||
@Composable
|
||||
@@ -73,7 +75,8 @@ fun MediaInputLayout(
|
||||
}
|
||||
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
Column(
|
||||
SnyggColumn(
|
||||
elementName = FlorisImeUi.Media.elementName,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.imeUiHeight()),
|
||||
@@ -82,14 +85,17 @@ fun MediaInputLayout(
|
||||
modifier = Modifier.weight(1f),
|
||||
fullEmojiMappings = emojiLayoutDataMap,
|
||||
)
|
||||
Row(
|
||||
SnyggRow(
|
||||
elementName = FlorisImeUi.MediaBottomRow.elementName,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.keyboardRowBaseHeight * 0.8f),
|
||||
) {
|
||||
KeyboardLikeButton(
|
||||
elementName = FlorisImeUi.MediaBottomRowButton.elementName,
|
||||
inputEventDispatcher = keyboardManager.inputEventDispatcher,
|
||||
keyData = TextKeyData.IME_UI_MODE_TEXT,
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
) {
|
||||
Text(
|
||||
text = "ABC",
|
||||
@@ -98,8 +104,10 @@ fun MediaInputLayout(
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
KeyboardLikeButton(
|
||||
elementName = FlorisImeUi.MediaBottomRowButton.elementName,
|
||||
inputEventDispatcher = keyboardManager.inputEventDispatcher,
|
||||
keyData = TextKeyData.DELETE,
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
) {
|
||||
Icon(imageVector = Icons.AutoMirrored.Outlined.Backspace, contentDescription = null)
|
||||
}
|
||||
@@ -113,42 +121,45 @@ internal fun KeyboardLikeButton(
|
||||
modifier: Modifier = Modifier,
|
||||
inputEventDispatcher: InputEventDispatcher,
|
||||
keyData: KeyData,
|
||||
element: String = FlorisImeUi.EmojiKey,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
elementName: String = FlorisImeUi.MediaEmojiKey.elementName,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
var isPressed by remember { mutableStateOf(false) }
|
||||
val keyStyle = FlorisImeTheme.style.get(
|
||||
element = element,
|
||||
code = keyData.code,
|
||||
isPressed = isPressed,
|
||||
)
|
||||
SnyggSurface(
|
||||
modifier = modifier.pointerInput(Unit) {
|
||||
awaitEachGesture {
|
||||
awaitFirstDown(requireUnconsumed = false).also {
|
||||
if (it.pressed != it.previousPressed) it.consume()
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val isPressed by interactionSource.collectIsPressedAsState()
|
||||
val selector = if (isPressed) {
|
||||
SnyggSelector.PRESSED
|
||||
} else {
|
||||
SnyggSelector.NONE
|
||||
}
|
||||
|
||||
SnyggBox(
|
||||
elementName = elementName,
|
||||
attributes = mapOf(FlorisImeUi.Attr.Code to keyData.code),
|
||||
selector = selector,
|
||||
clickAndSemanticsModifier = modifier
|
||||
.indication(interactionSource, ripple())
|
||||
.pointerInput(Unit) {
|
||||
awaitEachGesture {
|
||||
val down = awaitFirstDown(requireUnconsumed = false).also {
|
||||
if (it.pressed != it.previousPressed) it.consume()
|
||||
}
|
||||
val press = PressInteraction.Press(down.position)
|
||||
interactionSource.tryEmit(press)
|
||||
inputEventDispatcher.sendDown(keyData)
|
||||
inputFeedbackController.keyPress(keyData)
|
||||
val up = waitForUpOrCancellation()
|
||||
if (up != null) {
|
||||
interactionSource.tryEmit(PressInteraction.Release(press))
|
||||
inputEventDispatcher.sendUp(keyData)
|
||||
} else {
|
||||
interactionSource.tryEmit(PressInteraction.Cancel(press))
|
||||
inputEventDispatcher.sendCancel(keyData)
|
||||
}
|
||||
}
|
||||
isPressed = true
|
||||
inputEventDispatcher.sendDown(keyData)
|
||||
inputFeedbackController.keyPress(keyData)
|
||||
val up = waitForUpOrCancellation()
|
||||
isPressed = false
|
||||
if (up != null) {
|
||||
inputEventDispatcher.sendUp(keyData)
|
||||
} else {
|
||||
inputEventDispatcher.sendCancel(keyData)
|
||||
}
|
||||
}
|
||||
},
|
||||
style = keyStyle,
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.padding(horizontal = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
content = content,
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.PushPin
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.TabRowDefaults
|
||||
@@ -88,23 +88,22 @@ import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
|
||||
import dev.patrickgold.florisboard.lib.compose.header
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import kotlinx.coroutines.launch
|
||||
import org.florisboard.lib.android.AndroidKeyguardManager
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.systemService
|
||||
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 org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggThemeQuery
|
||||
import kotlin.math.ceil
|
||||
|
||||
private val EmojiCategoryValues = EmojiCategory.entries
|
||||
@@ -164,10 +163,6 @@ fun EmojiPaletteView(
|
||||
|
||||
val preferredSkinTone by prefs.emoji.preferredSkinTone.observeAsState()
|
||||
val emojiHistoryEnabled by prefs.emoji.historyEnabled.observeAsState()
|
||||
val fontSizeMultiplier = prefs.keyboard.fontSizeMultiplier()
|
||||
val emojiKeyStyle = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiKey)
|
||||
val emojiKeyFontSize = emojiKeyStyle.fontSize.spSize(default = EmojiDefaultFontSize) safeTimes fontSizeMultiplier
|
||||
val contentColor = emojiKeyStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
|
||||
var activeCategory by remember(emojiHistoryEnabled) {
|
||||
if (emojiHistoryEnabled) {
|
||||
@@ -182,11 +177,9 @@ fun EmojiPaletteView(
|
||||
|
||||
@Composable
|
||||
fun GridHeader(text: String) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.MediaEmojiSubheader.elementName,
|
||||
text = text,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -202,9 +195,6 @@ fun EmojiPaletteView(
|
||||
preferredSkinTone = preferredSkinTone,
|
||||
isPinned = isPinned,
|
||||
isRecent = isRecent,
|
||||
contentColor = contentColor,
|
||||
fontSize = emojiKeyFontSize,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
onEmojiInput = { emoji ->
|
||||
keyboardManager.inputEventDispatcher.sendDownUp(emoji)
|
||||
scope.launch {
|
||||
@@ -259,7 +249,6 @@ fun EmojiPaletteView(
|
||||
) {
|
||||
Text(
|
||||
text = stringRes(R.string.emoji__history__phone_locked_message),
|
||||
color = contentColor,
|
||||
)
|
||||
}
|
||||
} else if (activeCategory == EmojiCategory.RECENTLY_USED && isEmojiHistoryEmpty) {
|
||||
@@ -270,12 +259,10 @@ fun EmojiPaletteView(
|
||||
) {
|
||||
Text(
|
||||
text = stringRes(R.string.emoji__history__empty_message),
|
||||
color = contentColor,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
text = stringRes(R.string.emoji__history__usage_tip),
|
||||
color = contentColor,
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
}
|
||||
@@ -284,7 +271,7 @@ fun EmojiPaletteView(
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.florisScrollbar(lazyListState, color = contentColor.copy(alpha = 0.28f)),
|
||||
.florisScrollbar(lazyListState),
|
||||
columns = GridCells.Adaptive(minSize = EmojiBaseWidth),
|
||||
state = lazyListState,
|
||||
) {
|
||||
@@ -322,30 +309,29 @@ private fun EmojiCategoriesTabRow(
|
||||
onCategoryChange: (EmojiCategory) -> Unit,
|
||||
emojiHistoryEnabled: Boolean,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
val tabStyle = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiTab)
|
||||
val tabStyleFocused = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiTab, isFocus = true)
|
||||
val unselectedContentColor = tabStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
val selectedContentColor = tabStyleFocused.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
|
||||
val selectedTabIndex = if (emojiHistoryEnabled) {
|
||||
EmojiCategoryValues.indexOf(activeCategory)
|
||||
} else {
|
||||
EmojiCategoryValues.indexOf(activeCategory) - 1
|
||||
}
|
||||
val style = rememberSnyggThemeQuery(FlorisImeUi.MediaEmojiTab.elementName)
|
||||
TabRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.smartbarHeight),
|
||||
selectedTabIndex = selectedTabIndex,
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = selectedContentColor,
|
||||
contentColor = style.foreground(),
|
||||
indicator = { tabPositions ->
|
||||
val style = rememberSnyggThemeQuery(
|
||||
elementName = FlorisImeUi.MediaEmojiTab.elementName,
|
||||
selector = SnyggSelector.FOCUS,
|
||||
)
|
||||
TabRowDefaults.PrimaryIndicator(
|
||||
Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex]),
|
||||
color = selectedContentColor,
|
||||
height = 4.dp
|
||||
height = 4.dp,
|
||||
color = style.foreground(),
|
||||
)
|
||||
},
|
||||
) {
|
||||
@@ -359,13 +345,12 @@ private fun EmojiCategoriesTabRow(
|
||||
onCategoryChange(category)
|
||||
},
|
||||
selected = activeCategory == category,
|
||||
icon = { Icon(
|
||||
icon = { SnyggIcon(
|
||||
elementName = FlorisImeUi.MediaEmojiTab.elementName,
|
||||
selector = if (activeCategory == category) SnyggSelector.FOCUS else SnyggSelector.NONE,
|
||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
imageVector = category.icon(),
|
||||
contentDescription = null,
|
||||
) },
|
||||
unselectedContentColor = unselectedContentColor,
|
||||
selectedContentColor = selectedContentColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -378,9 +363,6 @@ private fun EmojiKey(
|
||||
preferredSkinTone: EmojiSkinTone,
|
||||
isPinned: Boolean,
|
||||
isRecent: Boolean,
|
||||
contentColor: Color,
|
||||
fontSize: TextUnit,
|
||||
fontSizeMultiplier: Float,
|
||||
onEmojiInput: (Emoji) -> Unit,
|
||||
onHistoryAction: () -> Unit,
|
||||
) {
|
||||
@@ -389,7 +371,7 @@ private fun EmojiKey(
|
||||
val variations = emojiSet.variations(withoutSkinTone = preferredSkinTone)
|
||||
var showVariantsBox by remember { mutableStateOf(false) }
|
||||
|
||||
Box(
|
||||
SnyggBox(FlorisImeUi.MediaEmojiKey.elementName,
|
||||
modifier = Modifier
|
||||
.aspectRatio(1f)
|
||||
.pointerInput(Unit) {
|
||||
@@ -413,10 +395,9 @@ private fun EmojiKey(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = base.value,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
color = contentColor,
|
||||
fontSize = fontSize,
|
||||
)
|
||||
if (variations.isNotEmpty() || isPinned || isRecent) {
|
||||
val style = rememberSnyggThemeQuery(FlorisImeUi.MediaEmojiKeyPopupExtendedIndicator.elementName)
|
||||
val shape = when (LocalLayoutDirection.current) {
|
||||
LayoutDirection.Ltr -> VariantsTriangleShapeLtr
|
||||
LayoutDirection.Rtl -> VariantsTriangleShapeRtl
|
||||
@@ -426,7 +407,7 @@ private fun EmojiKey(
|
||||
.align(Alignment.BottomEnd)
|
||||
.offset(x = (-4).dp, y = (-4).dp)
|
||||
.size(4.dp)
|
||||
.background(contentColor, shape),
|
||||
.background(style.foreground(), shape),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -448,7 +429,6 @@ private fun EmojiKey(
|
||||
variations = variations,
|
||||
visible = showVariantsBox,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
onEmojiTap = { emoji ->
|
||||
onEmojiInput(emoji)
|
||||
showVariantsBox = false
|
||||
@@ -467,13 +447,10 @@ private fun EmojiVariationsPopup(
|
||||
variations: List<Emoji>,
|
||||
visible: Boolean,
|
||||
emojiCompatInstance: EmojiCompat?,
|
||||
fontSizeMultiplier: Float,
|
||||
onEmojiTap: (Emoji) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val popupStyle = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiKeyPopup)
|
||||
val emojiKeyHeight = FlorisImeSizing.smartbarHeight
|
||||
val context = LocalContext.current
|
||||
|
||||
if (visible) {
|
||||
Popup(
|
||||
@@ -484,29 +461,25 @@ private fun EmojiVariationsPopup(
|
||||
},
|
||||
onDismissRequest = onDismiss,
|
||||
) {
|
||||
FlowRow(
|
||||
SnyggRow(
|
||||
elementName = FlorisImeUi.MediaEmojiKeyPopupBox.elementName,
|
||||
modifier = Modifier
|
||||
.widthIn(max = EmojiBaseWidth * 6)
|
||||
.snyggShadow(popupStyle)
|
||||
.snyggBorder(context, popupStyle)
|
||||
.snyggBackground(context, popupStyle, fallbackColor = FlorisImeTheme.fallbackSurfaceColor()),
|
||||
.widthIn(max = EmojiBaseWidth * 6),
|
||||
) {
|
||||
for (emoji in variations) {
|
||||
Box(
|
||||
SnyggBox(
|
||||
elementName = FlorisImeUi.MediaEmojiKeyPopupElement.elementName,
|
||||
modifier = Modifier
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures { onEmojiTap(emoji) }
|
||||
}
|
||||
.width(EmojiBaseWidth)
|
||||
.height(emojiKeyHeight)
|
||||
.padding(all = 4.dp),
|
||||
.height(emojiKeyHeight),
|
||||
) {
|
||||
EmojiText(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = emoji.value,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
color = popupStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
fontSize = popupStyle.fontSize.spSize(default = EmojiDefaultFontSize) safeTimes fontSizeMultiplier,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -526,7 +499,6 @@ private fun EmojiHistoryPopup(
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val scope = rememberCoroutineScope()
|
||||
val popupStyle = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiKeyPopup)
|
||||
val emojiKeyHeight = FlorisImeSizing.smartbarHeight
|
||||
val context = LocalContext.current
|
||||
val pinnedUS by prefs.emoji.historyPinnedUpdateStrategy.observeAsState()
|
||||
@@ -536,7 +508,8 @@ private fun EmojiHistoryPopup(
|
||||
|
||||
@Composable
|
||||
fun Action(icon: ImageVector, action: suspend () -> Unit) {
|
||||
Box(
|
||||
SnyggBox(
|
||||
elementName = FlorisImeUi.MediaEmojiKeyPopupElement.elementName,
|
||||
modifier = Modifier
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures {
|
||||
@@ -547,14 +520,11 @@ private fun EmojiHistoryPopup(
|
||||
}
|
||||
}
|
||||
.width(EmojiBaseWidth)
|
||||
.height(emojiKeyHeight)
|
||||
.padding(all = 4.dp),
|
||||
.height(emojiKeyHeight),
|
||||
) {
|
||||
Icon(
|
||||
SnyggIcon(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = popupStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -569,12 +539,10 @@ private fun EmojiHistoryPopup(
|
||||
},
|
||||
onDismissRequest = onDismiss,
|
||||
) {
|
||||
FlowRow(
|
||||
SnyggRow(
|
||||
elementName = FlorisImeUi.MediaEmojiKeyPopupBox.elementName,
|
||||
modifier = Modifier
|
||||
.widthIn(max = EmojiBaseWidth * 6)
|
||||
.snyggShadow(popupStyle)
|
||||
.snyggBorder(context, popupStyle)
|
||||
.snyggBackground(context, popupStyle, fallbackColor = FlorisImeTheme.fallbackSurfaceColor()),
|
||||
.widthIn(max = EmojiBaseWidth * 6),
|
||||
) {
|
||||
if (isCurrentlyPinned) {
|
||||
Action(
|
||||
|
||||
@@ -96,7 +96,7 @@ class NlpManager(context: Context) {
|
||||
prefs.suggestion.enabled.observeForever {
|
||||
assembleCandidates()
|
||||
}
|
||||
prefs.suggestion.clipboardContentEnabled.observeForever {
|
||||
prefs.clipboard.suggestionEnabled.observeForever {
|
||||
assembleCandidates()
|
||||
}
|
||||
prefs.emoji.suggestionEnabled.observeForever {
|
||||
@@ -370,14 +370,14 @@ class NlpManager(context: Context) {
|
||||
isPrivateSession: Boolean,
|
||||
): List<SuggestionCandidate> {
|
||||
// Check if enabled
|
||||
if (!prefs.suggestion.clipboardContentEnabled.get()) return emptyList()
|
||||
if (!prefs.clipboard.suggestionEnabled.get()) return emptyList()
|
||||
|
||||
val currentItem = validateClipboardItem(clipboardManager.primaryClip, lastClipboardItemId, content.text)
|
||||
?: return emptyList()
|
||||
|
||||
return buildList {
|
||||
val now = System.currentTimeMillis()
|
||||
if ((now - currentItem.creationTimestampMs) < prefs.suggestion.clipboardContentTimeout.get() * 1000) {
|
||||
if ((now - currentItem.creationTimestampMs) < prefs.clipboard.suggestionTimeout.get() * 1000) {
|
||||
add(ClipboardSuggestionCandidate(currentItem, sourceProvider = this@ClipboardSuggestionProvider, context = context))
|
||||
if (currentItem.isSensitive) {
|
||||
return@buildList
|
||||
|
||||
@@ -20,7 +20,6 @@ package dev.patrickgold.florisboard.ime.onehanded
|
||||
* Static object which contains all possible one-handed mode strings.
|
||||
*/
|
||||
enum class OneHandedMode {
|
||||
OFF,
|
||||
START,
|
||||
END;
|
||||
}
|
||||
|
||||
@@ -17,29 +17,26 @@
|
||||
package dev.patrickgold.florisboard.ime.onehanded
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.ZoomOutMap
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.input.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggIconButton
|
||||
|
||||
@Composable
|
||||
fun RowScope.OneHandedPanel(
|
||||
@@ -49,38 +46,43 @@ fun RowScope.OneHandedPanel(
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
val oneHandedPanelStyle = FlorisImeTheme.style.get(FlorisImeUi.OneHandedPanel)
|
||||
val context = LocalContext.current
|
||||
|
||||
Column(
|
||||
SnyggColumn(
|
||||
FlorisImeUi.OneHandedPanel.elementName,
|
||||
modifier = modifier
|
||||
.weight(weight)
|
||||
.snyggBackground(context, oneHandedPanelStyle)
|
||||
.height(FlorisImeSizing.imeUiHeight()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceEvenly,
|
||||
) {
|
||||
IconButton(
|
||||
SnyggIconButton(
|
||||
FlorisImeUi.OneHandedPanelButton.elementName,
|
||||
onClick = {
|
||||
inputFeedbackController.keyPress()
|
||||
prefs.keyboard.oneHandedMode.set(OneHandedMode.OFF)
|
||||
prefs.keyboard.oneHandedModeEnabled.set(false)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f),
|
||||
) {
|
||||
Icon(
|
||||
SnyggIcon(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
imageVector = Icons.Default.ZoomOutMap,
|
||||
contentDescription = stringRes(R.string.one_handed__close_btn_content_description),
|
||||
tint = oneHandedPanelStyle.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
SnyggIconButton(
|
||||
FlorisImeUi.OneHandedPanelButton.elementName,
|
||||
onClick = {
|
||||
inputFeedbackController.keyPress()
|
||||
prefs.keyboard.oneHandedMode.set(panelSide)
|
||||
},
|
||||
modifier = Modifier.weight(1f).fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Icon(
|
||||
SnyggIcon(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
imageVector = if (panelSide == OneHandedMode.START) {
|
||||
Icons.AutoMirrored.Filled.KeyboardArrowLeft
|
||||
} else {
|
||||
@@ -93,7 +95,6 @@ fun RowScope.OneHandedPanel(
|
||||
R.string.one_handed__move_end_btn_content_description
|
||||
}
|
||||
),
|
||||
tint = oneHandedPanelStyle.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,79 +17,55 @@
|
||||
package dev.patrickgold.florisboard.ime.popup
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.requiredHeight
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreHoriz
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import dev.patrickgold.florisboard.ime.keyboard.Key
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import org.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.snyggBorder
|
||||
import org.florisboard.lib.snygg.ui.snyggShadow
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
@Composable
|
||||
fun PopupBaseBox(
|
||||
modifier: Modifier = Modifier,
|
||||
key: Key,
|
||||
fontSizeMultiplier: Float,
|
||||
shouldIndicateExtendedPopups: Boolean,
|
||||
): Unit = with(LocalDensity.current) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val popupStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.KeyPopup,
|
||||
)
|
||||
val fontSize = popupStyle.fontSize.spSize() safeTimes fontSizeMultiplier
|
||||
SnyggSurface(
|
||||
SnyggBox(
|
||||
elementName = FlorisImeUi.KeyPopupBox.elementName,
|
||||
modifier = modifier,
|
||||
style = popupStyle,
|
||||
clip = true,
|
||||
) {
|
||||
key.label?.let { label ->
|
||||
Box(
|
||||
SnyggBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(key.visibleBounds.height.toDp())
|
||||
.align(Alignment.TopCenter),
|
||||
) {
|
||||
Text(
|
||||
SnyggText(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = label,
|
||||
color = popupStyle.foreground.solidColor(context),
|
||||
fontSize = fontSize,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (shouldIndicateExtendedPopups) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(fontSize.toDp() * 0.65f)
|
||||
.align(Alignment.CenterEnd),
|
||||
SnyggIcon(
|
||||
elementName = FlorisImeUi.KeyPopupExtendedIndicator.elementName,
|
||||
modifier = Modifier.align(Alignment.CenterEnd),
|
||||
imageVector = Icons.Default.MoreHoriz,
|
||||
contentDescription = null,
|
||||
tint = popupStyle.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -99,71 +75,40 @@ fun PopupBaseBox(
|
||||
fun PopupExtBox(
|
||||
modifier: Modifier = Modifier,
|
||||
elements: List<List<PopupUiController.Element>>,
|
||||
fontSizeMultiplier: Float,
|
||||
elemArrangement: Arrangement.Horizontal,
|
||||
elemWidth: Dp,
|
||||
elemHeight: Dp,
|
||||
activeElementIndex: Int,
|
||||
): Unit = with(LocalDensity.current) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val popupStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.KeyPopup,
|
||||
isFocus = false,
|
||||
)
|
||||
Column(
|
||||
modifier = modifier
|
||||
.snyggShadow(popupStyle)
|
||||
.snyggBorder(context, popupStyle)
|
||||
.snyggBackground(context, popupStyle),
|
||||
) {
|
||||
SnyggColumn(FlorisImeUi.KeyPopupBox.elementName, modifier = modifier) {
|
||||
for (row in elements.asReversed()) {
|
||||
Row(
|
||||
SnyggRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.requiredHeight(elemHeight),
|
||||
horizontalArrangement = elemArrangement,
|
||||
) {
|
||||
for (element in row) {
|
||||
val elemStyle = if (activeElementIndex == element.orderedIndex) {
|
||||
FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.KeyPopup,
|
||||
isFocus = true,
|
||||
)
|
||||
val selector = if (activeElementIndex == element.orderedIndex) {
|
||||
SnyggSelector.FOCUS
|
||||
} else {
|
||||
popupStyle
|
||||
null
|
||||
}
|
||||
val elemFontSize = elemStyle.fontSize.spSize() safeTimes fontSizeMultiplier safeTimes
|
||||
if (element.data.code == KeyCode.URI_COMPONENT_TLD) { 0.6f } else { 1.0f }
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(elemWidth, elemHeight)
|
||||
.run {
|
||||
if (activeElementIndex == element.orderedIndex) {
|
||||
snyggBackground(context, elemStyle)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
},
|
||||
SnyggBox(
|
||||
elementName = FlorisImeUi.KeyPopupElement.elementName,
|
||||
selector = selector,
|
||||
modifier = Modifier.size(elemWidth, elemHeight),
|
||||
) {
|
||||
element.label?.let { label ->
|
||||
Text(
|
||||
SnyggText(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = label,
|
||||
color = elemStyle.foreground.solidColor(context),
|
||||
fontSize = elemFontSize,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
}
|
||||
element.icon?.let { icon ->
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(elemFontSize.toDp() * 1.1f)
|
||||
.align(Alignment.Center),
|
||||
SnyggIcon(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = elemStyle.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +454,6 @@ class PopupUiController(
|
||||
.requiredSize(renderInfo.bounds.size.toDpSize())
|
||||
.absoluteOffset { renderInfo.bounds.topLeft.toIntOffset() },
|
||||
key = renderInfo.key,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
shouldIndicateExtendedPopups = renderInfo.shouldIndicateExtendedPopups && extRenderInfo == null,
|
||||
)
|
||||
}
|
||||
@@ -467,7 +466,6 @@ class PopupUiController(
|
||||
.requiredSize(renderInfo.bounds.size.toDpSize())
|
||||
.absoluteOffset { renderInfo.bounds.topLeft.toIntOffset() },
|
||||
elements = renderInfo.elements,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
elemArrangement = if (renderInfo.anchorLeft) {
|
||||
Arrangement.Start
|
||||
} else {
|
||||
|
||||
@@ -21,17 +21,11 @@ import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -45,25 +39,23 @@ import androidx.compose.ui.input.pointer.PointerInputChange
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.nlp.ClipboardSuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.conditional
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.SnyggSpacer
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
val CandidatesRowScrollbarHeight = 2.dp
|
||||
|
||||
@@ -78,13 +70,10 @@ fun CandidatesRow(modifier: Modifier = Modifier) {
|
||||
val displayMode by prefs.suggestion.displayMode.observeAsState()
|
||||
val candidates by nlpManager.activeCandidatesFlow.collectAsState()
|
||||
|
||||
val rowStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarCandidatesRow)
|
||||
val spacerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarCandidateSpacer)
|
||||
|
||||
Row(
|
||||
SnyggRow(
|
||||
elementName = FlorisImeUi.SmartbarCandidatesRow.elementName,
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.snyggBackground(context, rowStyle)
|
||||
.conditional(displayMode == CandidatesDisplayMode.DYNAMIC_SCROLLABLE && candidates.size > 1) {
|
||||
florisHorizontalScroll(scrollbarHeight = CandidatesRowScrollbarHeight)
|
||||
},
|
||||
@@ -115,12 +104,12 @@ fun CandidatesRow(modifier: Modifier = Modifier) {
|
||||
}
|
||||
for ((n, candidate) in list.withIndex()) {
|
||||
if (n > 0) {
|
||||
Spacer(
|
||||
SnyggSpacer(
|
||||
elementName = FlorisImeUi.SmartbarCandidateSpacer.elementName,
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.fillMaxHeight(0.6f)
|
||||
.align(Alignment.CenterVertically)
|
||||
.snyggBackground(context, spacerStyle),
|
||||
.align(Alignment.CenterVertically),
|
||||
)
|
||||
}
|
||||
CandidateItem(
|
||||
@@ -156,24 +145,18 @@ private fun CandidateItem(
|
||||
onLongPress: () -> Boolean = { false },
|
||||
longPressDelay: Long,
|
||||
) = with(LocalDensity.current) {
|
||||
val context = LocalContext.current
|
||||
var isPressed by remember { mutableStateOf(false) }
|
||||
|
||||
val style = if (candidate is ClipboardSuggestionCandidate) {
|
||||
FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.SmartbarCandidateClip,
|
||||
isPressed = isPressed,
|
||||
)
|
||||
val elementName = if (candidate is ClipboardSuggestionCandidate) {
|
||||
FlorisImeUi.SmartbarCandidateClip
|
||||
} else {
|
||||
FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.SmartbarCandidateWord,
|
||||
isPressed = isPressed,
|
||||
)
|
||||
}
|
||||
FlorisImeUi.SmartbarCandidateWord
|
||||
}.elementName
|
||||
|
||||
Row(
|
||||
SnyggRow(
|
||||
elementName = elementName,
|
||||
selector = if (isPressed) SnyggSelector.PRESSED else SnyggSelector.NONE,
|
||||
modifier = modifier
|
||||
.snyggBackground(context, style)
|
||||
.pointerInput(Unit) {
|
||||
awaitEachGesture {
|
||||
val down = awaitFirstDown()
|
||||
@@ -197,47 +180,27 @@ private fun CandidateItem(
|
||||
}
|
||||
isPressed = false
|
||||
}
|
||||
}
|
||||
.padding(horizontal = 12.dp),
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (candidate.icon != null) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(
|
||||
style.fontSize
|
||||
.spSize()
|
||||
.toDp() * 1.5f
|
||||
)
|
||||
.padding(end = 4.dp),
|
||||
imageVector = candidate.icon!!,
|
||||
contentDescription = null,
|
||||
tint = style.foreground.solidColor(context),
|
||||
)
|
||||
SnyggIcon(imageVector = candidate.icon!!)
|
||||
}
|
||||
Column(
|
||||
SnyggColumn(
|
||||
modifier = if (displayMode == CandidatesDisplayMode.CLASSIC) Modifier.weight(1f) else Modifier,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
SnyggText(
|
||||
elementName = null,
|
||||
attributes = mapOf("auto-commit" to if (candidate.isEligibleForAutoCommit) 1 else 0),
|
||||
text = candidate.text.toString(),
|
||||
color = style.foreground.solidColor(context),
|
||||
fontSize = style.fontSize.spSize(),
|
||||
fontWeight = if (candidate.isEligibleForAutoCommit) FontWeight.Bold else FontWeight.Normal,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
if (candidate.secondaryText != null) {
|
||||
Text(
|
||||
SnyggText(
|
||||
elementName = null,
|
||||
attributes = mapOf("auto-commit" to if (candidate.isEligibleForAutoCommit) 1 else 0),
|
||||
text = candidate.secondaryText!!.toString(),
|
||||
color = style.foreground.solidColor(context),
|
||||
fontSize = style.fontSize.spSize() safeTimes 0.6,
|
||||
fontWeight = if (candidate.isEligibleForAutoCommit) FontWeight.Bold else FontWeight.Normal,
|
||||
textAlign = TextAlign.Center,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -32,8 +33,22 @@ import androidx.compose.ui.layout.positionInParent
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofillSuggestion
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.toIntOffset
|
||||
import org.florisboard.lib.snygg.SnyggPropertySet
|
||||
import org.florisboard.lib.snygg.SnyggSinglePropertySet
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggThemeQuery
|
||||
|
||||
var CachedInlineSuggestionsChipStyleSet: SnyggSinglePropertySet? = null
|
||||
|
||||
@Composable
|
||||
fun InlineSuggestionsStyleCache() {
|
||||
val chipStyleSet = rememberSnyggThemeQuery(FlorisImeUi.InlineAutofillChip.elementName)
|
||||
LaunchedEffect(chipStyleSet) {
|
||||
CachedInlineSuggestionsChipStyleSet = chipStyleSet
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@Composable
|
||||
|
||||
@@ -25,22 +25,19 @@ import androidx.compose.animation.core.updateTransition
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.UnfoldLess
|
||||
import androidx.compose.material.icons.filled.UnfoldMore
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
@@ -61,7 +58,6 @@ import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionButton
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionsRow
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.ToggleOverflowPanelAction
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.horizontalTween
|
||||
@@ -70,10 +66,10 @@ import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.vectorResource
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
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.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggIconButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggThemeQuery
|
||||
|
||||
private const val AnimationDuration = 200
|
||||
|
||||
@@ -157,65 +153,47 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
|
||||
val shouldAnimate by prefs.smartbar.sharedActionsExpandWithAnimation.observeAsState()
|
||||
|
||||
val smartbarStyle = FlorisImeTheme.style.get(FlorisImeUi.Smartbar)
|
||||
val primaryActionsToggleStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarSharedActionsToggle)
|
||||
val secondaryActionsToggleStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarExtendedActionsToggle)
|
||||
|
||||
@Composable
|
||||
fun SharedActionsToggle() {
|
||||
IconButton(
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.SmartbarSharedActionsToggle.elementName,
|
||||
onClick = {
|
||||
if (/* was */ sharedActionsExpanded) {
|
||||
keyboardManager.activeState.isActionsOverflowVisible = false
|
||||
}
|
||||
prefs.smartbar.sharedActionsExpanded.set(!sharedActionsExpanded)
|
||||
},
|
||||
modifier = Modifier.sizeIn(maxHeight = FlorisImeSizing.smartbarHeight).aspectRatio(1f)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxHeight()
|
||||
.aspectRatio(1f)
|
||||
.snyggShadow(primaryActionsToggleStyle)
|
||||
.snyggBorder(context, primaryActionsToggleStyle)
|
||||
.snyggBackground(context, primaryActionsToggleStyle),
|
||||
contentAlignment = Alignment.Center,
|
||||
val transition = updateTransition(sharedActionsExpanded, label = "sharedActionsExpandedToggleBtn")
|
||||
val rotation by transition.animateFloat(
|
||||
transitionSpec = {
|
||||
if (shouldAnimate) AnimationTween else NoAnimationTween
|
||||
},
|
||||
label = "rotation",
|
||||
) {
|
||||
val transition = updateTransition(sharedActionsExpanded, label = "sharedActionsExpandedToggleBtn")
|
||||
val rotation by transition.animateFloat(
|
||||
transitionSpec = {
|
||||
if (shouldAnimate) AnimationTween else NoAnimationTween
|
||||
},
|
||||
label = "rotation",
|
||||
) {
|
||||
if (it) 180f else 0f
|
||||
}
|
||||
val arrowIcon = if (flipToggles) {
|
||||
Icons.AutoMirrored.Default.KeyboardArrowLeft
|
||||
} else {
|
||||
Icons.AutoMirrored.Default.KeyboardArrowRight
|
||||
}
|
||||
val incognitoIcon = vectorResource(id = R.drawable.ic_incognito)
|
||||
val incognitoDisplayMode = prefs.keyboard.incognitoDisplayMode.observeAsState()
|
||||
val isIncognitoMode = keyboardManager.activeState.isIncognitoMode
|
||||
val icon = if (isIncognitoMode) {
|
||||
when (incognitoDisplayMode.value) {
|
||||
IncognitoDisplayMode.REPLACE_SHARED_ACTIONS_TOGGLE -> incognitoIcon!!
|
||||
IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD -> arrowIcon
|
||||
}
|
||||
} else {
|
||||
arrowIcon
|
||||
}
|
||||
Icon(
|
||||
modifier = Modifier.rotate(if (incognitoDisplayMode.value == IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD) rotation else 0f),
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = primaryActionsToggleStyle.foreground.solidColor(
|
||||
context,
|
||||
default = FlorisImeTheme.fallbackContentColor()
|
||||
),
|
||||
)
|
||||
if (it) 180f else 0f
|
||||
}
|
||||
val arrowIcon = if (flipToggles) {
|
||||
Icons.AutoMirrored.Default.KeyboardArrowLeft
|
||||
} else {
|
||||
Icons.AutoMirrored.Default.KeyboardArrowRight
|
||||
}
|
||||
val incognitoIcon = vectorResource(id = R.drawable.ic_incognito)
|
||||
val incognitoDisplayMode = prefs.keyboard.incognitoDisplayMode.observeAsState()
|
||||
val isIncognitoMode = keyboardManager.activeState.isIncognitoMode
|
||||
val icon = if (isIncognitoMode) {
|
||||
when (incognitoDisplayMode.value) {
|
||||
IncognitoDisplayMode.REPLACE_SHARED_ACTIONS_TOGGLE -> incognitoIcon!!
|
||||
IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD -> arrowIcon
|
||||
}
|
||||
} else {
|
||||
arrowIcon
|
||||
}
|
||||
SnyggIcon(
|
||||
modifier = Modifier.rotate(if (incognitoDisplayMode.value == IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD) rotation else 0f),
|
||||
imageVector = icon,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,10 +224,10 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
exit = exitTransition,
|
||||
) {
|
||||
QuickActionsRow(
|
||||
FlorisImeUi.SmartbarSharedActionsRow.elementName,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.smartbarHeight),
|
||||
elementName = FlorisImeUi.SmartbarSharedActionsRow,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -257,7 +235,8 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
|
||||
@Composable
|
||||
fun ExtendedActionsToggle() {
|
||||
IconButton(
|
||||
SnyggIconButton(
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle.elementName,
|
||||
onClick = {
|
||||
if (/* was */ extendedActionsExpanded) {
|
||||
keyboardManager.activeState.isActionsOverflowVisible = false
|
||||
@@ -265,38 +244,25 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
prefs.smartbar.extendedActionsExpanded.set(!extendedActionsExpanded)
|
||||
},
|
||||
) {
|
||||
Box(
|
||||
val transition = updateTransition(extendedActionsExpanded, label = "smartbarSecondaryRowToggleBtn")
|
||||
val alpha by transition.animateFloat(label = "alpha") { if (it) 1f else 0f }
|
||||
val rotation by transition.animateFloat(label = "rotation") { if (it) 180f else 0f }
|
||||
// Expanded icon
|
||||
SnyggIcon(
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle.elementName,
|
||||
modifier = Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxHeight()
|
||||
.aspectRatio(1f)
|
||||
.snyggShadow(secondaryActionsToggleStyle)
|
||||
.snyggBorder(context, secondaryActionsToggleStyle)
|
||||
.snyggBackground(context, secondaryActionsToggleStyle),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val transition = updateTransition(extendedActionsExpanded, label = "smartbarSecondaryRowToggleBtn")
|
||||
val alpha by transition.animateFloat(label = "alpha") { if (it) 1f else 0f }
|
||||
val rotation by transition.animateFloat(label = "rotation") { if (it) 180f else 0f }
|
||||
// Expanded icon
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.alpha(alpha)
|
||||
.rotate(rotation),
|
||||
imageVector = Icons.Default.UnfoldLess,
|
||||
contentDescription = null,
|
||||
tint = secondaryActionsToggleStyle.foreground.solidColor(context),
|
||||
)
|
||||
// Not expanded icon
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.alpha(1f - alpha)
|
||||
.rotate(rotation - 180f),
|
||||
imageVector = Icons.Default.UnfoldMore,
|
||||
contentDescription = null,
|
||||
tint = secondaryActionsToggleStyle.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
.alpha(alpha)
|
||||
.rotate(rotation),
|
||||
imageVector = Icons.Default.UnfoldLess,
|
||||
)
|
||||
// Not expanded icon
|
||||
SnyggIcon(
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle.elementName,
|
||||
modifier = Modifier
|
||||
.alpha(1f - alpha)
|
||||
.rotate(rotation - 180f),
|
||||
imageVector = Icons.Default.UnfoldMore,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,11 +304,11 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
SnyggRow(
|
||||
FlorisImeUi.Smartbar.elementName,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.smartbarHeight)
|
||||
.snyggBackground(context, smartbarStyle),
|
||||
.height(FlorisImeSizing.smartbarHeight),
|
||||
) {
|
||||
when (smartbarLayout) {
|
||||
SmartbarLayout.SUGGESTIONS_ONLY -> {
|
||||
@@ -357,7 +323,7 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
if (shouldShowInlineSuggestionsUi) {
|
||||
InlineSuggestionsUi(inlineSuggestions)
|
||||
} else {
|
||||
QuickActionsRow(elementName = FlorisImeUi.SmartbarSharedActionsRow)
|
||||
QuickActionsRow(FlorisImeUi.SmartbarSharedActionsRow.elementName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,16 +356,16 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
|
||||
@Composable
|
||||
private fun SmartbarSecondaryRow(modifier: Modifier = Modifier) {
|
||||
val context = LocalContext.current
|
||||
val prefs by florisPreferenceModel()
|
||||
val smartbarLayout by prefs.smartbar.layout.observeAsState()
|
||||
val secondaryRowStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarExtendedActionsRow)
|
||||
val secondaryRowStyle = rememberSnyggThemeQuery(FlorisImeUi.SmartbarExtendedActionsRow.elementName)
|
||||
val windowStyle = rememberSnyggThemeQuery(FlorisImeUi.Window.elementName)
|
||||
val extendedActionsExpanded by prefs.smartbar.extendedActionsExpanded.observeAsState()
|
||||
val extendedActionsPlacement by prefs.smartbar.extendedActionsPlacement.observeAsState()
|
||||
val background = secondaryRowStyle.background.solidColor(context).let { color ->
|
||||
val background = secondaryRowStyle.background().let { color ->
|
||||
if (extendedActionsPlacement == ExtendedActionsPlacement.OVERLAY_APP_UI) {
|
||||
if (color.isUnspecified || color.alpha == 0f) {
|
||||
FlorisImeTheme.style.get(FlorisImeUi.Keyboard).background.solidColor(context, default = Color.Black)
|
||||
windowStyle.background(default = Color.Black)
|
||||
} else {
|
||||
color
|
||||
}
|
||||
@@ -414,11 +380,11 @@ private fun SmartbarSecondaryRow(modifier: Modifier = Modifier) {
|
||||
exit = VerticalExitTransition,
|
||||
) {
|
||||
QuickActionsRow(
|
||||
FlorisImeUi.SmartbarExtendedActionsRow.elementName,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.smartbarHeight)
|
||||
.background(background),
|
||||
elementName = FlorisImeUi.SmartbarExtendedActionsRow,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ fun QuickAction.computeDisplayName(evaluator: ComputingEvaluator): String {
|
||||
KeyCode.TOGGLE_AUTOCORRECT -> R.string.quick_action__toggle_autocorrect
|
||||
KeyCode.VOICE_INPUT -> R.string.quick_action__voice_input
|
||||
// TODO: In the future this will be merged into the resize keyboard panel, for now it is a separate action
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> R.string.quick_action__one_handed_mode
|
||||
KeyCode.TOGGLE_COMPACT_LAYOUT -> R.string.quick_action__one_handed_mode
|
||||
KeyCode.DRAG_MARKER -> if (evaluator.state.debugShowDragAndDropHelpers) {
|
||||
R.string.quick_action__drag_marker
|
||||
} else {
|
||||
@@ -133,7 +133,7 @@ fun QuickAction.computeTooltip(evaluator: ComputingEvaluator): String {
|
||||
KeyCode.TOGGLE_AUTOCORRECT -> R.string.quick_action__toggle_autocorrect__tooltip
|
||||
KeyCode.VOICE_INPUT -> R.string.quick_action__voice_input__tooltip
|
||||
// TODO: In the future this will be merged into the resize keyboard panel, for now it is a separate action
|
||||
KeyCode.COMPACT_LAYOUT_TO_RIGHT -> R.string.quick_action__one_handed_mode__tooltip
|
||||
KeyCode.TOGGLE_COMPACT_LAYOUT -> R.string.quick_action__one_handed_mode__tooltip
|
||||
KeyCode.DRAG_MARKER -> if (evaluator.state.debugShowDragAndDropHelpers) {
|
||||
R.string.quick_action__drag_marker__tooltip
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,7 @@ import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.plus
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
|
||||
private val QuickActionJsonConfig = Json(DefaultJsonConfig) {
|
||||
val QuickActionJsonConfig = Json(DefaultJsonConfig) {
|
||||
classDiscriminator = "$"
|
||||
encodeDefaults = false
|
||||
ignoreUnknownKeys = true
|
||||
@@ -61,7 +61,7 @@ data class QuickActionArrangement(
|
||||
QuickAction.InsertKey(TextKeyData.TOGGLE_INCOGNITO_MODE),
|
||||
QuickAction.InsertKey(TextKeyData.IME_UI_MODE_CLIPBOARD),
|
||||
QuickAction.InsertKey(TextKeyData.IME_UI_MODE_MEDIA),
|
||||
QuickAction.InsertKey(TextKeyData.COMPACT_LAYOUT_TO_RIGHT),
|
||||
QuickAction.InsertKey(TextKeyData.TOGGLE_COMPACT_LAYOUT),
|
||||
QuickAction.InsertKey(TextKeyData.TOGGLE_AUTOCORRECT),
|
||||
QuickAction.InsertKey(TextKeyData.ARROW_UP),
|
||||
QuickAction.InsertKey(TextKeyData.ARROW_DOWN),
|
||||
|
||||
@@ -16,11 +16,7 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.smartbar.quickaction
|
||||
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.waitForUpOrCancellation
|
||||
@@ -30,50 +26,33 @@ import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.foundation.interaction.collectIsPressedAsState
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.compose.tooltip.tooltip
|
||||
import dev.patrickgold.compose.tooltip.PlainTooltip
|
||||
import dev.patrickgold.florisboard.FlorisImeService
|
||||
import dev.patrickgold.florisboard.ime.keyboard.ComputingEvaluator
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeImageVector
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeLabel
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import org.florisboard.lib.snygg.ui.shape
|
||||
import org.florisboard.lib.snygg.ui.snyggBorder
|
||||
import org.florisboard.lib.snygg.ui.snyggClip
|
||||
import org.florisboard.lib.snygg.ui.snyggShadow
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
|
||||
private val BackgroundAnimationSpec = tween<Color>(durationMillis = 150, easing = FastOutSlowInEasing)
|
||||
private val DebugHelperColor = Color.Red.copy(alpha = 0.5f)
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
enum class QuickActionBarType {
|
||||
INTERACTIVE_BUTTON,
|
||||
INTERACTIVE_TILE,
|
||||
STATIC_TILE;
|
||||
EDITOR_TILE;
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -88,47 +67,17 @@ fun QuickActionButton(
|
||||
val inputFeedbackController = FlorisImeService.inputFeedbackController()
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val isPressed by interactionSource.collectIsPressedAsState()
|
||||
val isEnabled = type == QuickActionBarType.STATIC_TILE || evaluator.evaluateEnabled(action.keyData())
|
||||
val element = when (type) {
|
||||
val isEnabled = type == QuickActionBarType.EDITOR_TILE || evaluator.evaluateEnabled(action.keyData())
|
||||
val elementName = when (type) {
|
||||
QuickActionBarType.INTERACTIVE_BUTTON -> FlorisImeUi.SmartbarActionKey
|
||||
else -> FlorisImeUi.SmartbarActionTile
|
||||
QuickActionBarType.INTERACTIVE_TILE -> FlorisImeUi.SmartbarActionTile
|
||||
QuickActionBarType.EDITOR_TILE -> FlorisImeUi.SmartbarActionsEditorTile
|
||||
}.elementName
|
||||
val selector = when {
|
||||
isPressed -> SnyggSelector.PRESSED
|
||||
!isEnabled -> SnyggSelector.DISABLED
|
||||
else -> null
|
||||
}
|
||||
// We always need to know both state's styles to animate smoothly
|
||||
val actionStyleNotPressed = FlorisImeTheme.style.get(
|
||||
element = element,
|
||||
code = action.keyData().code,
|
||||
isPressed = false,
|
||||
isDisabled = !isEnabled,
|
||||
)
|
||||
val actionStylePressed = FlorisImeTheme.style.get(
|
||||
element = element,
|
||||
code = action.keyData().code,
|
||||
isPressed = true,
|
||||
isDisabled = !isEnabled,
|
||||
)
|
||||
val actionStyle = if (isPressed) actionStylePressed else actionStyleNotPressed
|
||||
val bgColor by animateColorAsState(
|
||||
targetValue = if (isPressed) {
|
||||
actionStylePressed.background.solidColor(context)
|
||||
} else {
|
||||
if (actionStyleNotPressed.background.solidColor(context).alpha == 0f) {
|
||||
actionStylePressed.background.solidColor(context).copy(0f)
|
||||
} else {
|
||||
actionStyleNotPressed.background.solidColor(context)
|
||||
}
|
||||
},
|
||||
animationSpec = BackgroundAnimationSpec, label = "bgColor",
|
||||
)
|
||||
val fgColor = when (action.keyData().code) {
|
||||
KeyCode.DRAG_MARKER -> {
|
||||
DebugHelperColor
|
||||
}
|
||||
|
||||
else -> {
|
||||
actionStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
}
|
||||
}
|
||||
val fgAlpha = if (action.keyData().code == KeyCode.NOOP) 0.5f else 1f
|
||||
|
||||
// Need to manually cancel an action if this composable suddenly leaves the composition to prevent the key from
|
||||
// being stuck in the pressed state
|
||||
@@ -140,92 +89,70 @@ fun QuickActionButton(
|
||||
}
|
||||
}
|
||||
|
||||
val tooltipModifier = if (type == QuickActionBarType.INTERACTIVE_BUTTON) {
|
||||
Modifier.tooltip(action.computeTooltip(evaluator))
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.aspectRatio(1f)
|
||||
.alpha(fgAlpha)
|
||||
.snyggShadow(actionStyle)
|
||||
.snyggBorder(context, actionStyle)
|
||||
.background(bgColor, actionStyle.shape.shape())
|
||||
.snyggClip(actionStyle)
|
||||
.indication(interactionSource, LocalIndication.current)
|
||||
.pointerInput(action, isEnabled) {
|
||||
awaitEachGesture {
|
||||
val down = awaitFirstDown()
|
||||
down.consume()
|
||||
if (isEnabled && type != QuickActionBarType.STATIC_TILE) {
|
||||
val press = PressInteraction.Press(down.position)
|
||||
inputFeedbackController?.keyPress(TextKeyData.UNSPECIFIED)
|
||||
interactionSource.tryEmit(press)
|
||||
action.onPointerDown(context)
|
||||
val up = waitForUpOrCancellation()
|
||||
if (up != null) {
|
||||
up.consume()
|
||||
interactionSource.tryEmit(PressInteraction.Release(press))
|
||||
action.onPointerUp(context)
|
||||
} else {
|
||||
interactionSource.tryEmit(PressInteraction.Cancel(press))
|
||||
action.onPointerCancel(context)
|
||||
PlainTooltip(action.computeTooltip(evaluator), enabled = type == QuickActionBarType.INTERACTIVE_BUTTON) {
|
||||
SnyggBox(
|
||||
elementName = elementName,
|
||||
attributes = mapOf(FlorisImeUi.Attr.Code to action.keyData().code),
|
||||
selector = selector,
|
||||
modifier = modifier,
|
||||
clickAndSemanticsModifier = Modifier
|
||||
.aspectRatio(1f)
|
||||
.indication(interactionSource, LocalIndication.current)
|
||||
.pointerInput(action, isEnabled) {
|
||||
awaitEachGesture {
|
||||
val down = awaitFirstDown()
|
||||
down.consume()
|
||||
if (isEnabled && type != QuickActionBarType.EDITOR_TILE) {
|
||||
val press = PressInteraction.Press(down.position)
|
||||
inputFeedbackController?.keyPress(TextKeyData.UNSPECIFIED)
|
||||
interactionSource.tryEmit(press)
|
||||
action.onPointerDown(context)
|
||||
val up = waitForUpOrCancellation()
|
||||
if (up != null) {
|
||||
up.consume()
|
||||
interactionSource.tryEmit(PressInteraction.Release(press))
|
||||
action.onPointerUp(context)
|
||||
} else {
|
||||
interactionSource.tryEmit(PressInteraction.Cancel(press))
|
||||
action.onPointerCancel(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.then(tooltipModifier)
|
||||
.padding(8.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
// Render foreground
|
||||
Box(
|
||||
modifier = Modifier.size(FlorisImeSizing.smartbarHeight * 0.5f),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
when (action) {
|
||||
is QuickAction.InsertKey -> {
|
||||
val (imageVector, label) = remember(action, evaluator) {
|
||||
evaluator.computeImageVector(action.data) to evaluator.computeLabel(action.data)
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
// Render foreground
|
||||
Box(
|
||||
modifier = Modifier.size(FlorisImeSizing.smartbarHeight * 0.5f),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
when (action) {
|
||||
is QuickAction.InsertKey -> {
|
||||
val (imageVector, label) = remember(action, evaluator) {
|
||||
evaluator.computeImageVector(action.data) to evaluator.computeLabel(action.data)
|
||||
}
|
||||
if (imageVector != null) {
|
||||
SnyggIcon(imageVector = imageVector)
|
||||
} else if (label != null) {
|
||||
SnyggText(text = label)
|
||||
}
|
||||
}
|
||||
if (imageVector != null) {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = null,
|
||||
tint = fgColor,
|
||||
)
|
||||
} else if (label != null) {
|
||||
Text(
|
||||
text = label,
|
||||
color = fgColor,
|
||||
|
||||
is QuickAction.InsertText -> {
|
||||
SnyggText(
|
||||
text = action.data.firstOrNull().toString().ifBlank { "?" },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is QuickAction.InsertText -> {
|
||||
Text(
|
||||
text = action.data.firstOrNull().toString().ifBlank { "?" },
|
||||
color = fgColor,
|
||||
fontSize = 16.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render additional info if this is a tile
|
||||
if (type != QuickActionBarType.INTERACTIVE_BUTTON) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = action.computeDisplayName(evaluator = evaluator),
|
||||
color = fgColor,
|
||||
fontSize = if (type == QuickActionBarType.STATIC_TILE) 10.sp else 13.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
// Render additional info if this is a tile
|
||||
if (type != QuickActionBarType.INTERACTIVE_BUTTON) {
|
||||
SnyggText(
|
||||
text = action.computeDisplayName(evaluator = evaluator),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ package dev.patrickgold.florisboard.ime.smartbar.quickaction
|
||||
|
||||
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
|
||||
@@ -34,7 +34,6 @@ import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -48,8 +47,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -59,25 +56,24 @@ import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.toIntOffset
|
||||
import org.florisboard.lib.snygg.SnyggPropertySet
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.snyggClip
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggIconButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
private const val ItemNotFound = -1
|
||||
private val NoopAction = QuickAction.InsertKey(TextKeyData(code = KeyCode.NOOP))
|
||||
private val DragMarkerAction = QuickAction.InsertKey(TextKeyData(code = KeyCode.DRAG_MARKER))
|
||||
|
||||
@Composable
|
||||
fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
fun QuickActionsEditorPanel() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
@@ -100,10 +96,6 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
var activeDragPosition by remember { mutableStateOf(IntOffset.Zero) }
|
||||
var activeDragSize by remember { mutableStateOf(IntSize.Zero) }
|
||||
|
||||
val panelStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditor)
|
||||
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorHeader)
|
||||
val subheaderStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorSubheader)
|
||||
|
||||
fun findItemForOffsetOrClosestInRow(offset: IntOffset): LazyGridItemInfo? {
|
||||
var closestItemInRow: LazyGridItemInfo? = null
|
||||
// Using manual for loop with indices instead of firstOrNull() because this method gets
|
||||
@@ -250,35 +242,34 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.snyggBackground(context, panelStyle, fallbackColor = FlorisImeTheme.fallbackSurfaceColor())
|
||||
.snyggClip(panelStyle),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.snyggBackground(context, headerStyle),
|
||||
SnyggColumn(FlorisImeUi.SmartbarActionsEditor.elementName, modifier = Modifier.safeDrawingPadding()) {
|
||||
SnyggRow(
|
||||
elementName = FlorisImeUi.SmartbarActionsEditorHeader.elementName,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
FlorisIconButton(
|
||||
onClick = {
|
||||
keyboardManager.activeState.isActionsEditorVisible = false
|
||||
},
|
||||
icon = Icons.AutoMirrored.Filled.KeyboardArrowLeft,
|
||||
iconColor = headerStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
)
|
||||
Text(
|
||||
// Extra box wrapper is needed to enforce size constraint but still allow for Snygg margin to be used
|
||||
Box(modifier = Modifier.size(48.dp)) {
|
||||
SnyggIconButton(
|
||||
elementName = FlorisImeUi.SmartbarActionsEditorHeaderButton.elementName,
|
||||
modifier = Modifier.fillMaxHeight().aspectRatio(1f),
|
||||
onClick = {
|
||||
keyboardManager.activeState.isActionsEditorVisible = false
|
||||
},
|
||||
) {
|
||||
SnyggIcon(
|
||||
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft,
|
||||
)
|
||||
}
|
||||
}
|
||||
SnyggText(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = stringRes(R.string.quick_actions_editor__header),
|
||||
color = headerStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
fontSize = headerStyle.fontSize.spSize(),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Spacer(Modifier.size(48.dp))
|
||||
}
|
||||
|
||||
Box {
|
||||
SnyggBox(FlorisImeUi.SmartbarActionsEditorTileGrid.elementName) {
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier
|
||||
.pointerInput(Unit) {
|
||||
@@ -296,7 +287,6 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
val n = if (stickyAction != NoopAction) 1 else 0
|
||||
Subheader(
|
||||
text = stringRes(R.string.quick_actions_editor__subheader_sticky_action, "n" to n),
|
||||
style = subheaderStyle,
|
||||
)
|
||||
}
|
||||
item(key = keyOf(stickyAction)) {
|
||||
@@ -304,14 +294,13 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
modifier = Modifier.animateItem(),
|
||||
action = stickyAction,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
type = QuickActionBarType.EDITOR_TILE,
|
||||
)
|
||||
}
|
||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||
val n = dynamicActions.count { it != NoopAction }
|
||||
Subheader(
|
||||
text = stringRes(R.string.quick_actions_editor__subheader_dynamic_actions, "n" to n),
|
||||
style = subheaderStyle,
|
||||
)
|
||||
}
|
||||
itemsIndexed(dynamicActions, key = { i, a -> keyOf(a) ?: i }) { _, action ->
|
||||
@@ -319,14 +308,13 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
modifier = Modifier.animateItem(),
|
||||
action = action,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
type = QuickActionBarType.EDITOR_TILE,
|
||||
)
|
||||
}
|
||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||
val n = hiddenActions.count { it != NoopAction }
|
||||
Subheader(
|
||||
text = stringRes(R.string.quick_actions_editor__subheader_hidden_actions, "n" to n),
|
||||
style = subheaderStyle,
|
||||
)
|
||||
}
|
||||
itemsIndexed(hiddenActions, key = { i, a -> keyOf(a) ?: i }) { _, action ->
|
||||
@@ -334,7 +322,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
modifier = Modifier.animateItem(),
|
||||
action = action,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
type = QuickActionBarType.EDITOR_TILE,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -349,28 +337,21 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
.offset(-size.width / 2, -size.height / 2),
|
||||
action = activeDragAction!!,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
type = QuickActionBarType.EDITOR_TILE,
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.systemBarsPadding().snyggBackground(context, panelStyle))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Subheader(
|
||||
text: String,
|
||||
style: SnyggPropertySet,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp, bottom = 8.dp, start = 16.dp, end = 16.dp),
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.SmartbarActionsEditorSubheader.elementName,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
text = text,
|
||||
color = style.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = style.fontSize.spSize() safeTimes 0.8f,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.smartbar.quickaction
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
@@ -31,17 +29,16 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import org.florisboard.lib.snygg.ui.SnyggButton
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
|
||||
@Composable
|
||||
fun QuickActionsOverflowPanel() {
|
||||
@@ -63,19 +60,15 @@ fun QuickActionsOverflowPanel() {
|
||||
actionArrangement.dynamicActions.takeLast(dynamicActionsCountToShow)
|
||||
}
|
||||
|
||||
val panelStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsOverflow)
|
||||
val buttonStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsOverflowCustomizeButton)
|
||||
|
||||
Box(
|
||||
SnyggBox(
|
||||
elementName = FlorisImeUi.SmartbarActionsOverflow.elementName,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.keyboardUiHeight())
|
||||
.snyggBackground(context, panelStyle),
|
||||
.height(FlorisImeSizing.keyboardUiHeight()),
|
||||
) {
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp),
|
||||
.fillMaxWidth(),
|
||||
columns = GridCells.Adaptive(FlorisImeSizing.smartbarHeight * 2.2f),
|
||||
) {
|
||||
items(visibleActions) { action ->
|
||||
@@ -87,13 +80,15 @@ fun QuickActionsOverflowPanel() {
|
||||
}
|
||||
item(span = { GridItemSpan(maxLineSpan) }) {
|
||||
SnyggButton(
|
||||
elementName = FlorisImeUi.SmartbarActionsOverflowCustomizeButton.elementName,
|
||||
onClick = { keyboardManager.activeState.isActionsEditorVisible = true },
|
||||
modifier = Modifier
|
||||
.wrapContentWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
text = stringRes(R.string.quick_actions_overflow__customize_actions_button),
|
||||
style = buttonStyle,
|
||||
)
|
||||
.wrapContentWidth(),
|
||||
) {
|
||||
SnyggText(
|
||||
text = stringRes(R.string.quick_actions_overflow__customize_actions_button),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package dev.patrickgold.florisboard.ime.smartbar.quickaction
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
@@ -32,10 +31,9 @@ import androidx.compose.ui.platform.LocalDensity
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.ui.SnyggRow
|
||||
|
||||
internal val ToggleOverflowPanelAction = QuickAction.InsertKey(TextKeyData.TOGGLE_ACTIONS_OVERFLOW)
|
||||
|
||||
@@ -67,8 +65,6 @@ fun QuickActionsRow(
|
||||
val showOverflowAction = actionArrangement.stickyAction != null ||
|
||||
smartbarLayout != SmartbarLayout.SUGGESTIONS_ACTIONS_SHARED || !sharedActionsExpanded
|
||||
|
||||
val rowStyle = FlorisImeTheme.style.get(elementName)
|
||||
|
||||
BoxWithConstraints(modifier = modifier.fillMaxSize()) {
|
||||
val width = constraints.maxWidth.toDp()
|
||||
val height = constraints.maxHeight.toDp()
|
||||
@@ -85,10 +81,9 @@ fun QuickActionsRow(
|
||||
}.coerceAtLeast(0)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.snyggBackground(context, rowStyle),
|
||||
SnyggRow(
|
||||
elementName = elementName,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
) {
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The FlorisBoard Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.text
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.util.launchUrl
|
||||
import org.florisboard.lib.snygg.SnyggPropertySet
|
||||
import org.florisboard.lib.snygg.ui.SnyggButton
|
||||
import org.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
|
||||
|
||||
@Composable
|
||||
fun HowDidWeGetHere() {
|
||||
val context = LocalContext.current
|
||||
val extensionManager by context.extensionManager()
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
val style = SnyggPropertySet(mapOf(
|
||||
"background" to SnyggSolidColorValue(Color.Yellow),
|
||||
"foreground" to SnyggSolidColorValue(Color.Black),
|
||||
"shape" to SnyggRoundedCornerDpShapeValue(16.dp, 16.dp, 16.dp, 16.dp, RoundedCornerShape(16.dp)),
|
||||
))
|
||||
|
||||
@Composable
|
||||
fun ColoredText(text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
color = style.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.keyboardUiHeight())
|
||||
.padding(8.dp),
|
||||
) {
|
||||
SnyggSurface(style = style) {
|
||||
Column(modifier = Modifier.padding(8.dp)) {
|
||||
ColoredText(text = "Challenge Complete! - How did we get here?\n")
|
||||
ColoredText(text = "You landed in a state which shouldn't be reachable, possibly related to the \"All keys invisible\" bug. Please report this bug and the steps to reproduce to the devs using the button below. Thanks!")
|
||||
Row {
|
||||
SnyggButton(
|
||||
onClick = {
|
||||
keyboardManager.activeState.rawValue = 0u
|
||||
extensionManager.init()
|
||||
},
|
||||
text = "Try reset keyboard",
|
||||
style = style,
|
||||
)
|
||||
SnyggButton(
|
||||
onClick = {
|
||||
context.launchUrl("https://github.com/florisboard/florisboard/issues/2362")
|
||||
},
|
||||
text = "Report bug to devs",
|
||||
style = style,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -33,16 +32,17 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.smartbar.IncognitoDisplayMode
|
||||
import dev.patrickgold.florisboard.ime.smartbar.InlineSuggestionsStyleCache
|
||||
import dev.patrickgold.florisboard.ime.smartbar.Smartbar
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionsOverflowPanel
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyboardLayout
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggColumn
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
|
||||
@Composable
|
||||
fun TextInputLayout(
|
||||
@@ -56,6 +56,8 @@ fun TextInputLayout(
|
||||
val state by keyboardManager.activeState.collectAsState()
|
||||
val evaluator by keyboardManager.activeEvaluator.collectAsState()
|
||||
|
||||
InlineSuggestionsStyleCache()
|
||||
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
@@ -67,31 +69,19 @@ fun TextInputLayout(
|
||||
QuickActionsOverflowPanel()
|
||||
} else {
|
||||
Box {
|
||||
val showIncognitoIcon = evaluator.state.isIncognitoMode && prefs.keyboard.incognitoDisplayMode.observeAsState().value == IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD
|
||||
val incognitoDisplayMode by prefs.keyboard.incognitoDisplayMode.observeAsState()
|
||||
val showIncognitoIcon = evaluator.state.isIncognitoMode &&
|
||||
incognitoDisplayMode == IncognitoDisplayMode.DISPLAY_BEHIND_KEYBOARD
|
||||
if (showIncognitoIcon) {
|
||||
val indicatorStyle = FlorisImeTheme.style.get(FlorisImeUi.IncognitoModeIndicator)
|
||||
Icon(
|
||||
SnyggIcon(
|
||||
FlorisImeUi.IncognitoModeIndicator.elementName,
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.align(Alignment.Center),
|
||||
painter = painterResource(R.drawable.ic_incognito),
|
||||
contentDescription = null,
|
||||
tint = indicatorStyle.foreground.solidColor(
|
||||
context, default = FlorisImeTheme.fallbackContentColor().copy(alpha = 0.067f),
|
||||
),
|
||||
)
|
||||
}
|
||||
val debugLayoutResult by keyboardManager.layoutManager
|
||||
.debugLayoutComputationResultFlow.collectAsState()
|
||||
if (state.keyboardMode != KeyboardMode.EDITING) {
|
||||
if (debugLayoutResult?.allLayoutsSuccess() == true) {
|
||||
TextKeyboardLayout(evaluator = evaluator)
|
||||
} else {
|
||||
HowDidWeGetHere()
|
||||
}
|
||||
} else {
|
||||
HowDidWeGetHere()
|
||||
}
|
||||
TextKeyboardLayout(evaluator = evaluator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ object KeyCode {
|
||||
const val CLIPBOARD_CLEAR_FULL_HISTORY = -37
|
||||
const val CLIPBOARD_CLEAR_PRIMARY_CLIP = -38
|
||||
|
||||
const val TOGGLE_COMPACT_LAYOUT = -110
|
||||
const val COMPACT_LAYOUT_TO_LEFT = -111
|
||||
const val COMPACT_LAYOUT_TO_RIGHT = -112
|
||||
const val SPLIT_LAYOUT = -113
|
||||
|
||||
@@ -121,6 +121,7 @@ class TextKeyData(
|
||||
CLIPBOARD_CLEAR_HISTORY,
|
||||
CLIPBOARD_CLEAR_FULL_HISTORY,
|
||||
CLIPBOARD_CLEAR_PRIMARY_CLIP,
|
||||
TOGGLE_COMPACT_LAYOUT,
|
||||
COMPACT_LAYOUT_TO_LEFT,
|
||||
COMPACT_LAYOUT_TO_RIGHT,
|
||||
UNDO,
|
||||
@@ -336,6 +337,12 @@ class TextKeyData(
|
||||
label = "clipboard_clear_primary_clip",
|
||||
)
|
||||
|
||||
/** Predefined key data for [KeyCode.TOGGLE_COMPACT_LAYOUT] */
|
||||
val TOGGLE_COMPACT_LAYOUT = TextKeyData(
|
||||
type = KeyType.SYSTEM_GUI,
|
||||
code = KeyCode.TOGGLE_COMPACT_LAYOUT,
|
||||
label = "toggle_compact_layout",
|
||||
)
|
||||
/** Predefined key data for [KeyCode.COMPACT_LAYOUT_TO_LEFT] */
|
||||
val COMPACT_LAYOUT_TO_LEFT = TextKeyData(
|
||||
type = KeyType.SYSTEM_GUI,
|
||||
|
||||
@@ -17,14 +17,16 @@
|
||||
package dev.patrickgold.florisboard.ime.text.keyboard
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.MotionEvent
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -55,7 +57,6 @@ import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -78,7 +79,6 @@ import dev.patrickgold.florisboard.ime.text.gestures.SwipeGesture
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyType
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.FlorisRect
|
||||
@@ -95,13 +95,15 @@ import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.onFailure
|
||||
import kotlinx.coroutines.isActive
|
||||
import org.florisboard.lib.android.isOrientationLandscape
|
||||
import org.florisboard.lib.snygg.ui.SnyggSurface
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.ui.SnyggBox
|
||||
import org.florisboard.lib.snygg.ui.SnyggIcon
|
||||
import org.florisboard.lib.snygg.ui.SnyggText
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggThemeQuery
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@SuppressLint("UnusedBoxWithConstraintsScope")
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun TextKeyboardLayout(
|
||||
@@ -119,8 +121,8 @@ fun TextKeyboardLayout(
|
||||
val glideEnabled = glideEnabledInternal && evaluator.editorInfo.isRichInputEditor &&
|
||||
evaluator.state.keyVariation != KeyVariation.PASSWORD
|
||||
val glideShowTrail by prefs.glide.showTrail.observeAsState()
|
||||
val glideTrailColor = FlorisImeTheme.style.get(element = FlorisImeUi.GlideTrail)
|
||||
.foreground.solidColor(context, default = Color.Green)
|
||||
val glideTrailStyle = rememberSnyggThemeQuery(FlorisImeUi.GlideTrail.elementName)
|
||||
val glideTrailColor = glideTrailStyle.foreground(default = Color.Green)
|
||||
|
||||
val controller = remember { TextKeyboardLayoutController(context) }.also {
|
||||
it.keyboard = keyboard
|
||||
@@ -295,7 +297,7 @@ fun TextKeyboardLayout(
|
||||
val debugShowTouchBoundaries by prefs.devtools.showKeyTouchBoundaries.observeAsState()
|
||||
for (textKey in keyboard.keys()) {
|
||||
TextKeyButton(
|
||||
textKey, evaluator, fontSizeMultiplier,
|
||||
textKey, evaluator,
|
||||
debugShowTouchBoundaries,
|
||||
)
|
||||
}
|
||||
@@ -316,49 +318,29 @@ fun TextKeyboardLayout(
|
||||
private fun TextKeyButton(
|
||||
key: TextKey,
|
||||
evaluator: ComputingEvaluator,
|
||||
fontSizeMultiplier: Float,
|
||||
debugShowTouchBoundaries: Boolean,
|
||||
) = with(LocalDensity.current) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val keyStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.Key,
|
||||
code = key.computedData.code,
|
||||
mode = evaluator.state.inputShiftState.value,
|
||||
isPressed = key.isPressed && key.isEnabled,
|
||||
isDisabled = !key.isEnabled,
|
||||
evaluator.keyboard.mode
|
||||
val attributes = mapOf(
|
||||
FlorisImeUi.Attr.Code to key.computedData.code,
|
||||
FlorisImeUi.Attr.Mode to evaluator.keyboard.mode.attrName(),
|
||||
FlorisImeUi.Attr.ShiftState to evaluator.state.inputShiftState.attrName(),
|
||||
)
|
||||
val fontSize = keyStyle.fontSize.spSize() safeTimes fontSizeMultiplier safeTimes when (key.computedData.code) {
|
||||
KeyCode.VIEW_CHARACTERS,
|
||||
KeyCode.VIEW_SYMBOLS,
|
||||
KeyCode.VIEW_SYMBOLS2 -> 0.80f
|
||||
KeyCode.VIEW_NUMERIC,
|
||||
KeyCode.VIEW_NUMERIC_ADVANCED -> 0.55f
|
||||
else -> 1.0f
|
||||
val selector = when {
|
||||
!key.isEnabled -> SnyggSelector.DISABLED
|
||||
key.isPressed -> SnyggSelector.PRESSED
|
||||
else -> SnyggSelector.NONE
|
||||
}
|
||||
val size = key.visibleBounds.size.toDpSize()
|
||||
Box(
|
||||
SnyggBox(
|
||||
FlorisImeUi.Key.elementName,
|
||||
attributes = attributes,
|
||||
selector = selector,
|
||||
modifier = Modifier
|
||||
.requiredSize(size)
|
||||
.absoluteOffset { key.visibleBounds.topLeft.toIntOffset() },
|
||||
) {
|
||||
// TODO: maybe make this customizable through a size property for keyStyle
|
||||
val isReducedHeight = key.computedData.let { it.code == KeyCode.ENTER || it.code == KeyCode.SPACE }
|
||||
SnyggSurface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.run {
|
||||
if (isReducedHeight && FlorisImeTheme.config.isBorderless) {
|
||||
this.padding(vertical = size.height * 0.15f)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
.fillMaxHeight(),
|
||||
style = keyStyle,
|
||||
clip = false,
|
||||
) { }
|
||||
val isTelpadKey = key.computedData.type == KeyType.NUMERIC && evaluator.keyboard.mode == KeyboardMode.PHONE
|
||||
val isTelPadKey = key.computedData.type == KeyType.NUMERIC && evaluator.keyboard.mode == KeyboardMode.PHONE
|
||||
key.label?.let { label ->
|
||||
var customLabel = label
|
||||
if (key.computedData.code == KeyCode.SPACE) {
|
||||
@@ -370,52 +352,29 @@ private fun TextKeyButton(
|
||||
SpaceBarMode.SPACE_BAR_KEY -> customLabel = "␣"
|
||||
}
|
||||
}
|
||||
Text(
|
||||
SnyggText(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.align(if (isTelpadKey) BiasAlignment(-0.5f, 0f) else Alignment.Center),
|
||||
.align(if (isTelPadKey) BiasAlignment(-0.5f, 0f) else Alignment.Center),
|
||||
text = customLabel,
|
||||
color = keyStyle.foreground.solidColor(context),
|
||||
fontSize = fontSize,
|
||||
maxLines = if (key.computedData.code == KeyCode.VIEW_NUMERIC_ADVANCED) 2 else 1,
|
||||
softWrap = key.computedData.code == KeyCode.VIEW_NUMERIC_ADVANCED,
|
||||
overflow = when (key.computedData.code) {
|
||||
KeyCode.SPACE -> TextOverflow.Ellipsis
|
||||
else -> TextOverflow.Visible
|
||||
},
|
||||
)
|
||||
}
|
||||
key.hintedLabel?.let { hintedLabel ->
|
||||
val keyHintStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.KeyHint,
|
||||
code = key.computedHintData.code,
|
||||
mode = evaluator.state.inputShiftState.value,
|
||||
isPressed = key.isPressed,
|
||||
)
|
||||
val hintFontSize = keyHintStyle.fontSize.spSize() safeTimes fontSizeMultiplier
|
||||
Text(
|
||||
SnyggText(
|
||||
elementName = FlorisImeUi.KeyHint.elementName,
|
||||
attributes = attributes,
|
||||
selector = selector,
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.align(if (isTelpadKey) BiasAlignment(0.5f, 0f) else Alignment.TopEnd)
|
||||
.snyggBackground(context, keyHintStyle)
|
||||
.padding(horizontal = (key.visibleBounds.width / 12f).toDp()),
|
||||
.align(if (isTelPadKey) BiasAlignment(0.5f, 0f) else Alignment.TopEnd),
|
||||
text = hintedLabel,
|
||||
color = keyHintStyle.foreground.solidColor(context),
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = hintFontSize,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
overflow = TextOverflow.Visible,
|
||||
)
|
||||
}
|
||||
key.foregroundImageVector?.let { imageVector ->
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(fontSize.toDp() * 1.1f)
|
||||
.align(Alignment.Center),
|
||||
SnyggIcon(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
imageVector = imageVector,
|
||||
contentDescription = null,
|
||||
tint = keyStyle.foreground.solidColor(context),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The FlorisBoard Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.theme
|
||||
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
import org.florisboard.lib.snygg.value.SnyggAssetResolver
|
||||
import java.net.URI
|
||||
|
||||
class FlorisAssetResolver(val context: Context, val themeInfo: ThemeManager.ThemeInfo) : SnyggAssetResolver {
|
||||
override fun resolveAbsolutePath(uri: String) = runCatching {
|
||||
val uri = URI.create(uri)
|
||||
require(uri.scheme == "flex")
|
||||
require(uri.authority.isNullOrEmpty())
|
||||
val baseDir = checkNotNull(themeInfo.loadedDir) { "Loaded directory was null" }
|
||||
val basePath = baseDir.canonicalPath
|
||||
val canonicalFile = baseDir.subFile(uri.path).canonicalFile
|
||||
val canonicalPath = canonicalFile.path
|
||||
check(canonicalPath.startsWith(basePath)) {
|
||||
"Calculated path '$canonicalPath' does not start with base path '$basePath'"
|
||||
}
|
||||
check(canonicalFile.exists()) {
|
||||
"Calculated path '$canonicalPath' does not exist"
|
||||
}
|
||||
check(canonicalFile.isFile()) {
|
||||
"Calculated path '$canonicalPath' is not a file"
|
||||
}
|
||||
canonicalPath
|
||||
}.onFailure { exception ->
|
||||
flogError { "FlorisAssetResolver failed to resolve URI '$uri'\n error: ${exception.message}\n with: $themeInfo" }
|
||||
}
|
||||
}
|
||||
@@ -18,97 +18,28 @@ package dev.patrickgold.florisboard.ime.theme
|
||||
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
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.CompositionLocalProvider
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.isUnspecified
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.input.InputShiftState
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.themeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.color.ColorMappings
|
||||
import org.florisboard.lib.snygg.Snygg
|
||||
import org.florisboard.lib.snygg.SnyggStylesheet
|
||||
import org.florisboard.lib.snygg.ui.ProvideSnyggUiDefaults
|
||||
import org.florisboard.lib.snygg.ui.SnyggUiDefaults
|
||||
import org.florisboard.lib.snygg.ui.ProvideSnyggTheme
|
||||
import org.florisboard.lib.snygg.ui.rememberSnyggTheme
|
||||
|
||||
private val LocalConfig = staticCompositionLocalOf<ThemeExtensionComponent> { error("not init") }
|
||||
private val LocalStyle = staticCompositionLocalOf<SnyggStylesheet> { error("not init") }
|
||||
|
||||
private val MaterialDarkFallbackPalette = darkColorScheme()
|
||||
private val MaterialLightFallbackPalette = lightColorScheme()
|
||||
|
||||
object FlorisImeTheme {
|
||||
val config: ThemeExtensionComponent
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalConfig.current
|
||||
|
||||
val style: SnyggStylesheet
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
get() = LocalStyle.current
|
||||
|
||||
@Composable
|
||||
fun fallbackSurfaceColor(): Color {
|
||||
return if (config.isNightTheme) Color.Black else Color.White
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun fallbackContentColor(): Color {
|
||||
return if (config.isNightTheme) Color.White else Color.Black
|
||||
}
|
||||
|
||||
fun init() {
|
||||
Snygg.init(
|
||||
stylesheetSpec = FlorisImeUiSpec,
|
||||
rulePreferredElementSorting = listOf(
|
||||
FlorisImeUi.Keyboard,
|
||||
FlorisImeUi.Key,
|
||||
FlorisImeUi.KeyHint,
|
||||
FlorisImeUi.KeyPopup,
|
||||
FlorisImeUi.Smartbar,
|
||||
FlorisImeUi.SmartbarSharedActionsRow,
|
||||
FlorisImeUi.SmartbarSharedActionsToggle,
|
||||
FlorisImeUi.SmartbarExtendedActionsRow,
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle,
|
||||
FlorisImeUi.SmartbarActionKey,
|
||||
FlorisImeUi.SmartbarActionTile,
|
||||
FlorisImeUi.SmartbarActionsOverflow,
|
||||
FlorisImeUi.SmartbarActionsOverflowCustomizeButton,
|
||||
FlorisImeUi.SmartbarActionsEditor,
|
||||
FlorisImeUi.SmartbarActionsEditorHeader,
|
||||
FlorisImeUi.SmartbarActionsEditorSubheader,
|
||||
FlorisImeUi.SmartbarCandidatesRow,
|
||||
FlorisImeUi.SmartbarCandidateWord,
|
||||
FlorisImeUi.SmartbarCandidateClip,
|
||||
FlorisImeUi.SmartbarCandidateSpacer,
|
||||
),
|
||||
rulePlaceholders = mapOf(
|
||||
"c:delete" to KeyCode.DELETE,
|
||||
"c:enter" to KeyCode.ENTER,
|
||||
"c:shift" to KeyCode.SHIFT,
|
||||
"c:space" to KeyCode.SPACE,
|
||||
"sh:unshifted" to InputShiftState.UNSHIFTED.value,
|
||||
"sh:shifted_manual" to InputShiftState.SHIFTED_MANUAL.value,
|
||||
"sh:shifted_automatic" to InputShiftState.SHIFTED_AUTOMATIC.value,
|
||||
"sh:caps_lock" to InputShiftState.CAPS_LOCK.value,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -122,31 +53,23 @@ fun FlorisImeTheme(content: @Composable () -> Unit) {
|
||||
val activeThemeInfo by themeManager.activeThemeInfo.observeAsNonNullState()
|
||||
val activeConfig = remember(activeThemeInfo) { activeThemeInfo.config }
|
||||
val activeStyle = remember(activeThemeInfo) { activeThemeInfo.stylesheet }
|
||||
val materialColors = if (activeConfig.isNightTheme) {
|
||||
if (AndroidVersion.ATLEAST_API31_S && accentColor.isUnspecified) {
|
||||
dynamicDarkColorScheme(context)
|
||||
} else {
|
||||
ColorMappings.getColorSchemeOrDefault(accentColor, activeConfig.isNightTheme)
|
||||
}
|
||||
} else {
|
||||
if (AndroidVersion.ATLEAST_API31_S && accentColor.isUnspecified) {
|
||||
dynamicLightColorScheme(context)
|
||||
} else {
|
||||
ColorMappings.getColorSchemeOrDefault(accentColor, activeConfig.isNightTheme)
|
||||
}
|
||||
|
||||
val assetResolver = remember(activeThemeInfo) {
|
||||
FlorisAssetResolver(context, activeThemeInfo)
|
||||
}
|
||||
MaterialTheme(materialColors) {
|
||||
val snyggTheme = rememberSnyggTheme(activeStyle, assetResolver)
|
||||
|
||||
MaterialTheme {
|
||||
CompositionLocalProvider(
|
||||
LocalConfig provides activeConfig,
|
||||
LocalStyle provides activeStyle,
|
||||
LocalTextStyle provides TextStyle.Default,
|
||||
) {
|
||||
val fallbackContentColor = FlorisImeTheme.fallbackContentColor()
|
||||
val fallbackSurfaceColor = FlorisImeTheme.fallbackSurfaceColor()
|
||||
val snyggUiDefaults = remember(fallbackContentColor, fallbackSurfaceColor) {
|
||||
SnyggUiDefaults(fallbackContentColor, fallbackSurfaceColor)
|
||||
}
|
||||
ProvideSnyggUiDefaults(snyggUiDefaults, content)
|
||||
ProvideSnyggTheme(
|
||||
snyggTheme = snyggTheme,
|
||||
dynamicAccentColor = accentColor,
|
||||
assetResolver = assetResolver,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,182 +16,291 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.theme
|
||||
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.florisboard.ime.input.InputShiftState
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import org.florisboard.lib.snygg.SnyggSelector
|
||||
import org.florisboard.lib.snygg.SnyggStylesheet
|
||||
|
||||
val FlorisImeThemeBaseStyle = SnyggStylesheet {
|
||||
val FlorisImeThemeBaseStyle = SnyggStylesheet.v2 {
|
||||
defines {
|
||||
"primary" to rgbaColor(76, 175, 80)
|
||||
"primaryVariant" to rgbaColor(56, 142, 60)
|
||||
"secondary" to rgbaColor(245, 124, 0)
|
||||
"secondaryVariant" to rgbaColor(230, 81, 0)
|
||||
"background" to rgbaColor(33, 33, 33)
|
||||
"surface" to rgbaColor(66, 66, 66)
|
||||
"surfaceVariant" to rgbaColor(97, 97, 97)
|
||||
"--primary" to rgbaColor(76, 175, 80)
|
||||
"--primary-variant" to rgbaColor(56, 142, 60)
|
||||
"--secondary" to rgbaColor(245, 124, 0)
|
||||
"--secondary-variant" to rgbaColor(230, 81, 0)
|
||||
"--background" to rgbaColor(33, 33, 33)
|
||||
"--surface" to rgbaColor(66, 66, 66)
|
||||
"--surface-variant" to rgbaColor(97, 97, 97)
|
||||
|
||||
"onBackground" to rgbaColor(255, 255, 255)
|
||||
"onSurface" to rgbaColor(255, 255, 255)
|
||||
"--on-primary" to rgbaColor(240, 240, 240)
|
||||
"--on-background" to rgbaColor(255, 255, 255)
|
||||
"--on-background-disabled" to rgbaColor(80, 80, 80)
|
||||
"--on-surface" to rgbaColor(255, 255, 255)
|
||||
|
||||
"--shape" to roundedCornerShape(8.dp)
|
||||
"--shape-variant" to roundedCornerShape(12.dp)
|
||||
}
|
||||
|
||||
FlorisImeUi.Keyboard {
|
||||
background = `var`("background")
|
||||
FlorisImeUi.Window.elementName {
|
||||
background = `var`("--background")
|
||||
foreground = `var`("--on-background")
|
||||
}
|
||||
FlorisImeUi.Key {
|
||||
background = `var`("surface")
|
||||
foreground = `var`("onSurface")
|
||||
fontSize = size(22.sp)
|
||||
|
||||
FlorisImeUi.Key.elementName {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
fontSize = fontSize(22.sp)
|
||||
shadowElevation = size(2.dp)
|
||||
shape = roundedCornerShape(20)
|
||||
shape = `var`("--shape")
|
||||
textMaxLines = textMaxLines(1)
|
||||
}
|
||||
FlorisImeUi.Key(pressedSelector = true) {
|
||||
background = `var`("surfaceVariant")
|
||||
foreground = `var`("onSurface")
|
||||
FlorisImeUi.Key.elementName(selector = SnyggSelector.PRESSED) {
|
||||
background = `var`("--surface-variant")
|
||||
foreground = `var`("--on-surface")
|
||||
}
|
||||
FlorisImeUi.Key(codes = listOf(KeyCode.ENTER)) {
|
||||
background = `var`("primary")
|
||||
foreground = `var`("onSurface")
|
||||
FlorisImeUi.Key.elementName(FlorisImeUi.Attr.Code to listOf(KeyCode.ENTER)) {
|
||||
background = `var`("--primary")
|
||||
foreground = `var`("--on-surface")
|
||||
}
|
||||
FlorisImeUi.Key(codes = listOf(KeyCode.ENTER), pressedSelector = true) {
|
||||
background = `var`("primaryVariant")
|
||||
foreground = `var`("onSurface")
|
||||
FlorisImeUi.Key.elementName(FlorisImeUi.Attr.Code to listOf(KeyCode.ENTER), selector = SnyggSelector.PRESSED) {
|
||||
background = `var`("--primary-variant")
|
||||
foreground = `var`("--on-surface")
|
||||
}
|
||||
FlorisImeUi.Key(
|
||||
codes = listOf(KeyCode.SHIFT),
|
||||
modes = listOf(InputShiftState.CAPS_LOCK.value),
|
||||
FlorisImeUi.Key.elementName(FlorisImeUi.Attr.Code to listOf(KeyCode.SPACE)) {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
fontSize = fontSize(12.sp)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.Key.elementName(FlorisImeUi.Attr.Code to listOf(
|
||||
KeyCode.VIEW_CHARACTERS,
|
||||
KeyCode.VIEW_SYMBOLS,
|
||||
KeyCode.VIEW_SYMBOLS2,
|
||||
)) {
|
||||
fontSize = fontSize(18.sp)
|
||||
}
|
||||
FlorisImeUi.Key.elementName(FlorisImeUi.Attr.Code to listOf(
|
||||
KeyCode.VIEW_NUMERIC,
|
||||
KeyCode.VIEW_NUMERIC_ADVANCED,
|
||||
)) {
|
||||
fontSize = fontSize(12.sp)
|
||||
}
|
||||
FlorisImeUi.Key.elementName(FlorisImeUi.Attr.Code to listOf(KeyCode.VIEW_NUMERIC_ADVANCED)) {
|
||||
textMaxLines = textMaxLines(2)
|
||||
}
|
||||
FlorisImeUi.Key.elementName(
|
||||
FlorisImeUi.Attr.Code to listOf(KeyCode.SHIFT),
|
||||
FlorisImeUi.Attr.ShiftState to listOf(InputShiftState.CAPS_LOCK.attrName()),
|
||||
) {
|
||||
foreground = rgbaColor(255, 152, 0)
|
||||
}
|
||||
FlorisImeUi.Key(codes = listOf(KeyCode.SPACE)) {
|
||||
background = `var`("surface")
|
||||
foreground = rgbaColor(144, 144, 144)
|
||||
fontSize = size(12.sp)
|
||||
}
|
||||
FlorisImeUi.KeyHint {
|
||||
FlorisImeUi.KeyHint.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = rgbaColor(184, 184, 184)
|
||||
fontSize = size(12.sp)
|
||||
foreground = `var`("--on-surface-variant")
|
||||
fontFamily = genericFontFamily(FontFamily.Monospace)
|
||||
fontSize = fontSize(12.sp)
|
||||
padding = padding(0.dp, 1.dp, 1.dp, 0.dp)
|
||||
textMaxLines = textMaxLines(1)
|
||||
}
|
||||
FlorisImeUi.KeyPopup {
|
||||
FlorisImeUi.KeyPopupBox.elementName {
|
||||
background = rgbaColor(117, 117, 117)
|
||||
foreground = `var`("onSurface")
|
||||
fontSize = size(22.sp)
|
||||
shape = roundedCornerShape(20)
|
||||
foreground = `var`("--on-surface")
|
||||
fontSize = fontSize(22.sp)
|
||||
shape = `var`("--shape")
|
||||
shadowElevation = size(2.dp)
|
||||
}
|
||||
FlorisImeUi.KeyPopup(focusSelector = true) {
|
||||
FlorisImeUi.KeyPopupElement.elementName(selector = SnyggSelector.FOCUS) {
|
||||
background = rgbaColor(189, 189, 189)
|
||||
foreground = `var`("onSurface")
|
||||
fontSize = size(22.sp)
|
||||
shape = roundedCornerShape(20)
|
||||
shape = `var`("--shape")
|
||||
}
|
||||
FlorisImeUi.KeyPopupExtendedIndicator.elementName {
|
||||
fontSize = fontSize(16.sp)
|
||||
}
|
||||
|
||||
FlorisImeUi.ClipboardHeader {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = `var`("onSurface")
|
||||
fontSize = size(16.sp)
|
||||
FlorisImeUi.Smartbar.elementName {
|
||||
fontSize = fontSize(18.sp)
|
||||
}
|
||||
FlorisImeUi.ClipboardItem {
|
||||
background = `var`("surface")
|
||||
foreground = `var`("onSurface")
|
||||
fontSize = size(14.sp)
|
||||
shape = roundedCornerShape(12.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardItemPopup {
|
||||
background = rgbaColor(117, 117, 117)
|
||||
foreground = `var`("onSurface")
|
||||
fontSize = size(14.sp)
|
||||
shape = roundedCornerShape(12.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardEnableHistoryButton {
|
||||
background = `var`("primary")
|
||||
foreground = rgbaColor(0, 0, 0)
|
||||
shape = roundedCornerShape(12.dp)
|
||||
}
|
||||
|
||||
FlorisImeUi.EmojiKey {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = `var`("onBackground")
|
||||
fontSize = size(22.sp)
|
||||
shape = roundedCornerShape(20)
|
||||
}
|
||||
FlorisImeUi.EmojiKey(pressedSelector = true) {
|
||||
background = `var`("surface")
|
||||
foreground = `var`("onSurface")
|
||||
}
|
||||
|
||||
FlorisImeUi.GlideTrail {
|
||||
foreground = `var`("primary")
|
||||
}
|
||||
|
||||
FlorisImeUi.IncognitoModeIndicator {
|
||||
foreground = rgbaColor(255, 255, 255, 0.067f)
|
||||
}
|
||||
|
||||
FlorisImeUi.OneHandedPanel {
|
||||
background = rgbaColor(27, 94, 32)
|
||||
foreground = rgbaColor(238, 238, 238)
|
||||
}
|
||||
|
||||
FlorisImeUi.Smartbar {
|
||||
FlorisImeUi.SmartbarSharedActionsRow.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
}
|
||||
FlorisImeUi.SmartbarSharedActionsRow {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
}
|
||||
FlorisImeUi.SmartbarSharedActionsToggle {
|
||||
background = `var`("surface")
|
||||
foreground = `var`("onSurface")
|
||||
FlorisImeUi.SmartbarSharedActionsToggle.elementName {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
shape = circleShape()
|
||||
}
|
||||
FlorisImeUi.SmartbarExtendedActionsRow {
|
||||
FlorisImeUi.SmartbarExtendedActionsRow.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
}
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle {
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = rgbaColor(144, 144, 144)
|
||||
shape = circleShape()
|
||||
}
|
||||
FlorisImeUi.SmartbarActionKey {
|
||||
FlorisImeUi.SmartbarActionKey.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = rgbaColor(220, 220, 220)
|
||||
fontSize = size(18.sp)
|
||||
shape = `var`("--shape")
|
||||
clip = yes()
|
||||
}
|
||||
FlorisImeUi.SmartbarActionKey.elementName(selector = SnyggSelector.DISABLED) {
|
||||
foreground = `var`("--on-background-disabled")
|
||||
}
|
||||
FlorisImeUi.SmartbarActionTile.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = `var`("--on-background")
|
||||
margin = padding(4.dp)
|
||||
shape = roundedCornerShape(20)
|
||||
clip = yes()
|
||||
textMaxLines = textMaxLines(2)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.SmartbarActionKey(pressedSelector = true) {
|
||||
background = `var`("surface")
|
||||
foreground = rgbaColor(220, 220, 220)
|
||||
FlorisImeUi.SmartbarActionTile.elementName(selector = SnyggSelector.DISABLED) {
|
||||
foreground = `var`("--on-background-disabled")
|
||||
}
|
||||
FlorisImeUi.SmartbarActionKey(disabledSelector = true) {
|
||||
FlorisImeUi.SmartbarActionsOverflowCustomizeButton.elementName {
|
||||
background = `var`("--primary")
|
||||
foreground = `var`("--on-primary")
|
||||
shape = roundedCornerShape(24.dp)
|
||||
}
|
||||
|
||||
FlorisImeUi.SmartbarActionsEditor.elementName {
|
||||
background = `var`("--background")
|
||||
foreground = `var`("--on-background")
|
||||
shape = roundedCornerShape(24.dp, 24.dp, 0.dp, 0.dp)
|
||||
clip = yes()
|
||||
}
|
||||
FlorisImeUi.SmartbarActionsEditorHeader.elementName {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
fontSize = fontSize(16.sp)
|
||||
textMaxLines = textMaxLines(1)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.SmartbarActionsEditorSubheader.elementName {
|
||||
foreground = `var`("--secondary")
|
||||
fontSize = fontSize(16.sp)
|
||||
fontWeight = fontWeight(FontWeight.Bold)
|
||||
padding = padding(12.dp, 16.dp, 12.dp, 8.dp)
|
||||
textMaxLines = textMaxLines(1)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.SmartbarActionsEditorTileGrid.elementName {
|
||||
margin = padding(4.dp, 0.dp)
|
||||
}
|
||||
FlorisImeUi.SmartbarActionsEditorTile.elementName {
|
||||
margin = padding(4.dp)
|
||||
padding = padding(8.dp)
|
||||
textAlign = textAlign(TextAlign.Center)
|
||||
textMaxLines = textMaxLines(2)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.SmartbarActionsEditorTile.elementName(FlorisImeUi.Attr.Code to listOf(KeyCode.NOOP)) {
|
||||
foreground = `var`("--on-background-disabled")
|
||||
}
|
||||
FlorisImeUi.SmartbarActionsEditorTile.elementName(FlorisImeUi.Attr.Code to listOf(KeyCode.DRAG_MARKER)) {
|
||||
foreground = rgbaColor(255, 0, 0)
|
||||
}
|
||||
|
||||
FlorisImeUi.SmartbarCandidateWord.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = `var`("surface")
|
||||
}
|
||||
FlorisImeUi.SmartbarCandidateWord {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = rgbaColor(220, 220, 220)
|
||||
fontSize = size(14.sp)
|
||||
foreground = `var`("--on-background")
|
||||
fontSize = fontSize(14.sp)
|
||||
margin = padding(4.dp)
|
||||
padding = padding(8.dp, 0.dp)
|
||||
shape = rectangleShape()
|
||||
textMaxLines = textMaxLines(1)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.SmartbarCandidateWord(pressedSelector = true) {
|
||||
background = `var`("surface")
|
||||
foreground = rgbaColor(220, 220, 220)
|
||||
FlorisImeUi.SmartbarCandidateWord.elementName(selector = SnyggSelector.PRESSED) {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
}
|
||||
FlorisImeUi.SmartbarCandidateClip {
|
||||
FlorisImeUi.SmartbarCandidateClip.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = rgbaColor(220, 220, 220)
|
||||
fontSize = size(14.sp)
|
||||
fontSize = fontSize(14.sp)
|
||||
margin = padding(4.dp)
|
||||
padding = padding(8.dp, 0.dp)
|
||||
shape = roundedCornerShape(8)
|
||||
textMaxLines = textMaxLines(1)
|
||||
textOverflow = textOverflow(TextOverflow.Ellipsis)
|
||||
}
|
||||
FlorisImeUi.SmartbarCandidateClip(pressedSelector = true) {
|
||||
background = `var`("surface")
|
||||
foreground = rgbaColor(220, 220, 220)
|
||||
FlorisImeUi.SmartbarCandidateClip.elementName(selector = SnyggSelector.PRESSED) {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
}
|
||||
FlorisImeUi.SmartbarCandidateSpacer {
|
||||
FlorisImeUi.SmartbarCandidateSpacer.elementName {
|
||||
foreground = rgbaColor(255, 255, 255, 0.25f)
|
||||
}
|
||||
|
||||
FlorisImeUi.SystemNavBar {
|
||||
background = `var`("background")
|
||||
FlorisImeUi.ClipboardHeader.elementName {
|
||||
foreground = `var`("--on-background")
|
||||
fontSize = fontSize(16.sp)
|
||||
}
|
||||
FlorisImeUi.ClipboardSubheader.elementName {
|
||||
fontSize = fontSize(14.sp)
|
||||
margin = padding(6.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardContent.elementName {
|
||||
padding = padding(10.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardItem.elementName {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
fontSize = fontSize(14.sp)
|
||||
margin = padding(4.dp)
|
||||
padding = padding(12.dp, 8.dp)
|
||||
shape = `var`("--shape-variant")
|
||||
clip = yes()
|
||||
shadowElevation = size(2.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardItemPopup.elementName {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
margin = padding(4.dp)
|
||||
shape = `var`("--shape-variant")
|
||||
clip = yes()
|
||||
shadowElevation = size(2.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardItemPopupAction.elementName {
|
||||
fontSize = fontSize(16.sp)
|
||||
padding = padding(12.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardItemPopupActionText.elementName {
|
||||
margin = padding(8.dp, 0.dp, 0.dp, 0.dp)
|
||||
}
|
||||
FlorisImeUi.ClipboardHistoryDisabledButton.elementName {
|
||||
background = `var`("--primary")
|
||||
foreground = `var`("--on-primary")
|
||||
shape = roundedCornerShape(24.dp)
|
||||
}
|
||||
|
||||
FlorisImeUi.MediaEmojiKey.elementName {
|
||||
background = rgbaColor(0, 0, 0, 0f)
|
||||
foreground = `var`("--on-background")
|
||||
fontSize = fontSize(22.sp)
|
||||
shape = `var`("--shape")
|
||||
}
|
||||
FlorisImeUi.MediaEmojiKey.elementName(selector = SnyggSelector.PRESSED) {
|
||||
background = `var`("--surface")
|
||||
foreground = `var`("--on-surface")
|
||||
}
|
||||
|
||||
FlorisImeUi.GlideTrail.elementName {
|
||||
foreground = `var`("--primary")
|
||||
}
|
||||
|
||||
FlorisImeUi.IncognitoModeIndicator.elementName {
|
||||
foreground = rgbaColor(255, 255, 255, 0.067f)
|
||||
}
|
||||
|
||||
FlorisImeUi.OneHandedPanel.elementName {
|
||||
background = rgbaColor(27, 94, 32)
|
||||
foreground = rgbaColor(238, 238, 238)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,47 +16,307 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.theme
|
||||
|
||||
object FlorisImeUi {
|
||||
const val Keyboard = "keyboard"
|
||||
const val Key = "key"
|
||||
const val KeyHint = "key-hint"
|
||||
const val KeyPopup = "key-popup"
|
||||
import dev.patrickgold.florisboard.R
|
||||
|
||||
const val ClipboardHeader = "clipboard-header"
|
||||
const val ClipboardItem = "clipboard-item"
|
||||
const val ClipboardItemPopup = "clipboard-item-popup"
|
||||
const val ClipboardEnableHistoryButton = "clipboard-enable-history-button"
|
||||
enum class FlorisImeUi(val elementName: String, val resId: Int?) {
|
||||
Root(
|
||||
elementName = "root",
|
||||
resId = R.string.snygg__rule_element__root,
|
||||
),
|
||||
Window(
|
||||
elementName = "window",
|
||||
resId = R.string.snygg__rule_element__window,
|
||||
),
|
||||
|
||||
const val EmojiKey = "emoji-key"
|
||||
const val EmojiKeyPopup = "emoji-key-popup"
|
||||
const val EmojiTab = "emoji-tab"
|
||||
Key(
|
||||
elementName = "key",
|
||||
resId = R.string.snygg__rule_element__key,
|
||||
),
|
||||
KeyHint(
|
||||
elementName = "key-hint",
|
||||
resId = R.string.snygg__rule_element__key_hint,
|
||||
),
|
||||
KeyPopupBox(
|
||||
elementName = "key-popup-box",
|
||||
resId = R.string.snygg__rule_element__key_popup_box,
|
||||
),
|
||||
KeyPopupElement(
|
||||
elementName = "key-popup-element",
|
||||
resId = R.string.snygg__rule_element__key_popup_element,
|
||||
),
|
||||
KeyPopupExtendedIndicator(
|
||||
elementName = "key-popup-extended-indicator",
|
||||
resId = R.string.snygg__rule_element__key_popup_extended_indicator,
|
||||
),
|
||||
|
||||
const val ExtractedLandscapeInputLayout = "extracted-landscape-input-layout"
|
||||
const val ExtractedLandscapeInputField = "extracted-landscape-input-field"
|
||||
const val ExtractedLandscapeInputAction = "extracted-landscape-input-action"
|
||||
ClipboardHeader(
|
||||
elementName = "clipboard-header",
|
||||
resId = R.string.snygg__rule_element__clipboard_header,
|
||||
),
|
||||
ClipboardHeaderButton(
|
||||
elementName = "clipboard-header-button",
|
||||
resId = R.string.snygg__rule_element__clipboard_header_button,
|
||||
),
|
||||
ClipboardHeaderText(
|
||||
elementName = "clipboard-header-text",
|
||||
resId = R.string.snygg__rule_element__clipboard_header_text,
|
||||
),
|
||||
ClipboardSubheader(
|
||||
elementName = "clipboard-subheader",
|
||||
resId = R.string.snygg__rule_element__clipboard_subheader,
|
||||
),
|
||||
ClipboardContent(
|
||||
elementName = "clipboard-content",
|
||||
resId = R.string.snygg__rule_element__clipboard_content,
|
||||
),
|
||||
ClipboardItem(
|
||||
elementName = "clipboard-item",
|
||||
resId = R.string.snygg__rule_element__clipboard_item,
|
||||
),
|
||||
ClipboardItemPopup(
|
||||
elementName = "clipboard-item-popup",
|
||||
resId = R.string.snygg__rule_element__clipboard_item_popup,
|
||||
),
|
||||
ClipboardItemPopupAction(
|
||||
elementName = "clipboard-item-popup-action",
|
||||
resId = R.string.snygg__rule_element__clipboard_item_popup_action,
|
||||
),
|
||||
ClipboardItemPopupActionIcon(
|
||||
elementName = "clipboard-item-popup-action-icon",
|
||||
resId = R.string.snygg__rule_element__clipboard_item_popup_action_icon,
|
||||
),
|
||||
ClipboardItemPopupActionText(
|
||||
elementName = "clipboard-item-popup-action-text",
|
||||
resId = R.string.snygg__rule_element__clipboard_item_popup_action_text,
|
||||
),
|
||||
ClipboardClearAllDialog(
|
||||
elementName = "clipboard-clear-all-dialog",
|
||||
resId = R.string.snygg__rule_element__clipboard_clear_all_dialog,
|
||||
),
|
||||
ClipboardClearAllDialogMessage(
|
||||
elementName = "clipboard-clear-all-dialog-message",
|
||||
resId = R.string.snygg__rule_element__clipboard_clear_all_dialog_message,
|
||||
),
|
||||
ClipboardClearAllDialogButtons(
|
||||
elementName = "clipboard-clear-all-dialog-buttons",
|
||||
resId = R.string.snygg__rule_element__clipboard_clear_all_dialog_buttons,
|
||||
),
|
||||
ClipboardClearAllDialogButton(
|
||||
elementName = "clipboard-clear-all-dialog-button",
|
||||
resId = R.string.snygg__rule_element__clipboard_clear_all_dialog_button,
|
||||
),
|
||||
ClipboardHistoryDisabledTitle(
|
||||
elementName = "clipboard-history-disabled-title",
|
||||
resId = R.string.snygg__rule_element__clipboard_history_disabled_title,
|
||||
),
|
||||
ClipboardHistoryDisabledMessage(
|
||||
elementName = "clipboard-history-disabled-message",
|
||||
resId = R.string.snygg__rule_element__clipboard_history_disabled_message,
|
||||
),
|
||||
ClipboardHistoryDisabledButton(
|
||||
elementName = "clipboard-history-disabled-button",
|
||||
resId = R.string.snygg__rule_element__clipboard_history_disabled_button,
|
||||
),
|
||||
ClipboardHistoryLockedTitle(
|
||||
elementName = "clipboard-history-locked-title",
|
||||
resId = R.string.snygg__rule_element__clipboard_history_locked_title,
|
||||
),
|
||||
ClipboardHistoryLockedMessage(
|
||||
elementName = "clipboard-history-locked-message",
|
||||
resId = R.string.snygg__rule_element__clipboard_history_locked_message,
|
||||
),
|
||||
|
||||
const val GlideTrail = "glide-trail"
|
||||
ExtractedLandscapeInputLayout(
|
||||
elementName = "extracted-landscape-input-layout",
|
||||
resId = R.string.snygg__rule_element__extracted_landscape_input_layout,
|
||||
),
|
||||
ExtractedLandscapeInputField(
|
||||
elementName = "extracted-landscape-input-field",
|
||||
resId = R.string.snygg__rule_element__extracted_landscape_input_field,
|
||||
),
|
||||
ExtractedLandscapeInputAction(
|
||||
elementName = "extracted-landscape-input-action",
|
||||
resId = R.string.snygg__rule_element__extracted_landscape_input_action,
|
||||
),
|
||||
|
||||
const val IncognitoModeIndicator = "incognito-mode-indicator"
|
||||
GlideTrail(
|
||||
elementName = "glide-trail",
|
||||
resId = R.string.snygg__rule_element__glide_trail,
|
||||
),
|
||||
|
||||
const val OneHandedPanel = "one-handed-panel"
|
||||
IncognitoModeIndicator(
|
||||
elementName = "incognito-mode-indicator",
|
||||
resId = R.string.snygg__rule_element__incognito_mode_indicator,
|
||||
),
|
||||
|
||||
const val Smartbar = "smartbar"
|
||||
const val SmartbarSharedActionsRow = "smartbar-shared-actions-row"
|
||||
const val SmartbarSharedActionsToggle = "smartbar-shared-actions-toggle"
|
||||
const val SmartbarExtendedActionsRow = "smartbar-extended-actions-row"
|
||||
const val SmartbarExtendedActionsToggle = "smartbar-extended-actions-toggle"
|
||||
const val SmartbarActionKey = "smartbar-action-key"
|
||||
const val SmartbarActionTile = "smartbar-action-tile"
|
||||
const val SmartbarActionsOverflow = "smartbar-actions-overflow"
|
||||
const val SmartbarActionsOverflowCustomizeButton = "smartbar-actions-overflow-customize-button"
|
||||
const val SmartbarActionsEditor = "smartbar-actions-editor"
|
||||
const val SmartbarActionsEditorHeader = "smartbar-actions-editor-header"
|
||||
const val SmartbarActionsEditorSubheader = "smartbar-actions-editor-subheader"
|
||||
const val SmartbarCandidatesRow = "smartbar-candidates-row"
|
||||
const val SmartbarCandidateWord = "smartbar-candidate-word"
|
||||
const val SmartbarCandidateClip = "smartbar-candidate-clip"
|
||||
const val SmartbarCandidateSpacer = "smartbar-candidate-spacer"
|
||||
InlineAutofillChip(
|
||||
elementName = "inline-autofill-chip",
|
||||
resId = R.string.snygg__rule_element__inline_autofill_chip,
|
||||
),
|
||||
|
||||
const val SystemNavBar = "system-nav-bar"
|
||||
Media(
|
||||
elementName = "media",
|
||||
resId = R.string.snygg__rule_element__media,
|
||||
),
|
||||
|
||||
MediaEmojiSubheader(
|
||||
elementName = "media-emoji-subheader",
|
||||
resId = R.string.snygg__rule_element__media_emoji_subheader,
|
||||
),
|
||||
MediaEmojiKey(
|
||||
elementName = "media-emoji-key",
|
||||
resId = R.string.snygg__rule_element__media_emoji_key,
|
||||
),
|
||||
MediaEmojiKeyPopupBox(
|
||||
elementName = "media-emoji-key-popup-box",
|
||||
resId = R.string.snygg__rule_element__media_emoji_key_popup_box,
|
||||
),
|
||||
MediaEmojiKeyPopupElement(
|
||||
elementName = "media-emoji-key-popup-element",
|
||||
resId = R.string.snygg__rule_element__media_emoji_key_popup_element,
|
||||
),
|
||||
MediaEmojiKeyPopupExtendedIndicator(
|
||||
elementName = "media-emoji-key-popup-extended-indicator",
|
||||
resId = R.string.snygg__rule_element__media_emoji_key_popup_extended_indicator,
|
||||
),
|
||||
MediaEmojiTab(
|
||||
elementName = "media-emoji-tab",
|
||||
resId = R.string.snygg__rule_element__media_emoji_tab,
|
||||
),
|
||||
|
||||
MediaBottomRow(
|
||||
elementName = "media-bottom-row",
|
||||
resId = R.string.snygg__rule_element__media_bottom_row,
|
||||
),
|
||||
MediaBottomRowButton(
|
||||
elementName = "media-bottom-row-button",
|
||||
resId = R.string.snygg__rule_element__media_bottom_row_button,
|
||||
),
|
||||
|
||||
OneHandedPanel(
|
||||
elementName = "one-handed-panel",
|
||||
resId = R.string.snygg__rule_element__one_handed_panel,
|
||||
),
|
||||
OneHandedPanelButton(
|
||||
elementName = "one-handed-panel-button",
|
||||
resId = R.string.snygg__rule_element__one_handed_panel_button,
|
||||
),
|
||||
|
||||
Smartbar(
|
||||
elementName = "smartbar",
|
||||
resId = R.string.snygg__rule_element__smartbar,
|
||||
),
|
||||
SmartbarSharedActionsRow(
|
||||
elementName = "smartbar-shared-actions-row",
|
||||
resId = R.string.snygg__rule_element__smartbar_shared_actions_row,
|
||||
),
|
||||
SmartbarSharedActionsToggle(
|
||||
elementName = "smartbar-shared-actions-toggle",
|
||||
resId = R.string.snygg__rule_element__smartbar_shared_actions_toggle,
|
||||
),
|
||||
SmartbarExtendedActionsRow(
|
||||
elementName = "smartbar-extended-actions-row",
|
||||
resId = R.string.snygg__rule_element__smartbar_extended_actions_row,
|
||||
),
|
||||
SmartbarExtendedActionsToggle(
|
||||
elementName = "smartbar-extended-actions-toggle",
|
||||
resId = R.string.snygg__rule_element__smartbar_extended_actions_toggle,
|
||||
),
|
||||
SmartbarActionKey(
|
||||
elementName = "smartbar-action-key",
|
||||
resId = R.string.snygg__rule_element__smartbar_action_key,
|
||||
),
|
||||
SmartbarActionTile(
|
||||
elementName = "smartbar-action-tile",
|
||||
resId = R.string.snygg__rule_element__smartbar_action_tile,
|
||||
),
|
||||
SmartbarActionsOverflow(
|
||||
elementName = "smartbar-actions-overflow",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_overflow,
|
||||
),
|
||||
SmartbarActionsOverflowCustomizeButton(
|
||||
elementName = "smartbar-actions-overflow-customize-button",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_overflow_customize_button,
|
||||
),
|
||||
|
||||
SmartbarActionsEditor(
|
||||
elementName = "smartbar-actions-editor",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_editor,
|
||||
),
|
||||
SmartbarActionsEditorHeader(
|
||||
elementName = "smartbar-actions-editor-header",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_editor_header,
|
||||
),
|
||||
SmartbarActionsEditorHeaderButton(
|
||||
elementName = "smartbar-actions-editor-header-button",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_editor_header_button,
|
||||
),
|
||||
SmartbarActionsEditorSubheader(
|
||||
elementName = "smartbar-actions-editor-subheader",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_editor_subheader,
|
||||
),
|
||||
SmartbarActionsEditorTileGrid(
|
||||
elementName = "smartbar-actions-editor-tile-grid",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_editor_tile_grid,
|
||||
),
|
||||
SmartbarActionsEditorTile(
|
||||
elementName = "smartbar-actions-editor-tile",
|
||||
resId = R.string.snygg__rule_element__smartbar_actions_editor_tile,
|
||||
),
|
||||
|
||||
SmartbarCandidatesRow(
|
||||
elementName = "smartbar-candidates-row",
|
||||
resId = R.string.snygg__rule_element__smartbar_candidates_row,
|
||||
),
|
||||
SmartbarCandidateWord(
|
||||
elementName = "smartbar-candidate-word",
|
||||
resId = R.string.snygg__rule_element__smartbar_candidate_word,
|
||||
),
|
||||
SmartbarCandidateClip(
|
||||
elementName = "smartbar-candidate-clip",
|
||||
resId = R.string.snygg__rule_element__smartbar_candidate_clip,
|
||||
),
|
||||
SmartbarCandidateSpacer(
|
||||
elementName = "smartbar-candidate-spacer",
|
||||
resId = R.string.snygg__rule_element__smartbar_candidate_spacer,
|
||||
),
|
||||
|
||||
SubtypePanel(
|
||||
elementName = "subtype-panel",
|
||||
resId = R.string.snygg__rule_element__subtype_panel,
|
||||
),
|
||||
SubtypePanelHeader(
|
||||
elementName = "subtype-panel-header",
|
||||
resId = R.string.snygg__rule_element__subtype_panel_header,
|
||||
);
|
||||
|
||||
companion object {
|
||||
val elementNames by lazy { entries.map { it.elementName } }
|
||||
|
||||
val elementNamesToOrdinals by lazy {
|
||||
val enumEntries = entries
|
||||
buildMap {
|
||||
enumEntries.forEach { entry ->
|
||||
put(entry.elementName, entry.ordinal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val elementNamesToTranslation by lazy {
|
||||
val enumEntries = entries
|
||||
buildMap {
|
||||
put("defines", R.string.snygg__rule_annotation__defines)
|
||||
put("font", R.string.snygg__rule_annotation__font)
|
||||
enumEntries.forEach { entry ->
|
||||
put(entry.elementName, entry.resId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Attr {
|
||||
const val Code = "code"
|
||||
const val Mode = "mode"
|
||||
const val ShiftState = "shiftstate"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,41 +16,42 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.theme
|
||||
|
||||
/*
|
||||
import org.florisboard.lib.snygg.Snygg
|
||||
import org.florisboard.lib.snygg.SnyggLevel
|
||||
import org.florisboard.lib.snygg.SnyggPropertySetSpecBuilder
|
||||
import org.florisboard.lib.snygg.SnyggSpec
|
||||
import org.florisboard.lib.snygg.SnyggPropertySetSpecDeclBuilder
|
||||
import org.florisboard.lib.snygg.SnyggSpecDecl
|
||||
import org.florisboard.lib.snygg.value.SnyggCircleShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggCutCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggCutCornerPercentShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDpSizeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggMaterialYouDarkColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggMaterialYouLightColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDynamicColorDarkColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggDynamicColorLightColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRectangleShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRoundedCornerDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggRoundedCornerPercentShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggStaticColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSpSizeValue
|
||||
|
||||
fun SnyggPropertySetSpecBuilder.background() {
|
||||
fun SnyggPropertySetSpecDeclBuilder.background() {
|
||||
property(
|
||||
name = Snygg.Background,
|
||||
level = SnyggLevel.BASIC,
|
||||
supportedValues(SnyggSolidColorValue, SnyggMaterialYouLightColorValue, SnyggMaterialYouDarkColorValue),
|
||||
supportedValues(SnyggStaticColorValue, SnyggDynamicColorLightColorValue, SnyggDynamicColorDarkColorValue),
|
||||
)
|
||||
}
|
||||
fun SnyggPropertySetSpecBuilder.foreground() {
|
||||
fun SnyggPropertySetSpecDeclBuilder.foreground() {
|
||||
property(
|
||||
name = Snygg.Foreground,
|
||||
level = SnyggLevel.BASIC,
|
||||
supportedValues(SnyggSolidColorValue, SnyggMaterialYouLightColorValue, SnyggMaterialYouDarkColorValue),
|
||||
supportedValues(SnyggStaticColorValue, SnyggDynamicColorLightColorValue, SnyggDynamicColorDarkColorValue),
|
||||
)
|
||||
}
|
||||
fun SnyggPropertySetSpecBuilder.border() {
|
||||
fun SnyggPropertySetSpecDeclBuilder.border() {
|
||||
property(
|
||||
name = Snygg.BorderColor,
|
||||
level = SnyggLevel.ADVANCED,
|
||||
supportedValues(SnyggSolidColorValue, SnyggMaterialYouLightColorValue, SnyggMaterialYouDarkColorValue),
|
||||
supportedValues(SnyggStaticColorValue, SnyggDynamicColorLightColorValue, SnyggDynamicColorDarkColorValue),
|
||||
)
|
||||
property(
|
||||
name = Snygg.BorderWidth,
|
||||
@@ -58,21 +59,21 @@ fun SnyggPropertySetSpecBuilder.border() {
|
||||
supportedValues(SnyggDpSizeValue),
|
||||
)
|
||||
}
|
||||
fun SnyggPropertySetSpecBuilder.font() {
|
||||
fun SnyggPropertySetSpecDeclBuilder.font() {
|
||||
property(
|
||||
name = Snygg.FontSize,
|
||||
level = SnyggLevel.ADVANCED,
|
||||
supportedValues(SnyggSpSizeValue),
|
||||
)
|
||||
}
|
||||
fun SnyggPropertySetSpecBuilder.shadow() {
|
||||
fun SnyggPropertySetSpecDeclBuilder.shadow() {
|
||||
property(
|
||||
name = Snygg.ShadowElevation,
|
||||
level = SnyggLevel.ADVANCED,
|
||||
supportedValues(SnyggDpSizeValue),
|
||||
)
|
||||
}
|
||||
fun SnyggPropertySetSpecBuilder.shape() {
|
||||
fun SnyggPropertySetSpecDeclBuilder.shape() {
|
||||
property(
|
||||
name = Snygg.Shape,
|
||||
level = SnyggLevel.ADVANCED,
|
||||
@@ -87,7 +88,7 @@ fun SnyggPropertySetSpecBuilder.shape() {
|
||||
)
|
||||
}
|
||||
|
||||
object FlorisImeUiSpec : SnyggSpec({
|
||||
object FlorisImeUiSpec : SnyggSpecDecl({
|
||||
element(FlorisImeUi.Keyboard) {
|
||||
background()
|
||||
}
|
||||
@@ -276,3 +277,40 @@ object FlorisImeUiSpec : SnyggSpec({
|
||||
background()
|
||||
}
|
||||
})
|
||||
|
||||
Snygg.init(
|
||||
stylesheetSpec = FlorisImeUiSpec,
|
||||
rulePreferredElementSorting = listOf(
|
||||
FlorisImeUi.Keyboard,
|
||||
FlorisImeUi.Key,
|
||||
FlorisImeUi.KeyHint,
|
||||
FlorisImeUi.KeyPopup,
|
||||
FlorisImeUi.Smartbar,
|
||||
FlorisImeUi.SmartbarSharedActionsRow,
|
||||
FlorisImeUi.SmartbarSharedActionsToggle,
|
||||
FlorisImeUi.SmartbarExtendedActionsRow,
|
||||
FlorisImeUi.SmartbarExtendedActionsToggle,
|
||||
FlorisImeUi.SmartbarActionKey,
|
||||
FlorisImeUi.SmartbarActionTile,
|
||||
FlorisImeUi.SmartbarActionsOverflow,
|
||||
FlorisImeUi.SmartbarActionsOverflowCustomizeButton,
|
||||
FlorisImeUi.SmartbarActionsEditor,
|
||||
FlorisImeUi.SmartbarActionsEditorHeader,
|
||||
FlorisImeUi.SmartbarActionsEditorSubheader,
|
||||
FlorisImeUi.SmartbarCandidatesRow,
|
||||
FlorisImeUi.SmartbarCandidateWord,
|
||||
FlorisImeUi.SmartbarCandidateClip,
|
||||
FlorisImeUi.SmartbarCandidateSpacer,
|
||||
),
|
||||
rulePlaceholders = mapOf(
|
||||
"c:delete" to KeyCode.DELETE,
|
||||
"c:enter" to KeyCode.ENTER,
|
||||
"c:shift" to KeyCode.SHIFT,
|
||||
"c:space" to KeyCode.SPACE,
|
||||
"sh:unshifted" to InputShiftState.UNSHIFTED.value,
|
||||
"sh:shifted_manual" to InputShiftState.SHIFTED_MANUAL.value,
|
||||
"sh:shifted_automatic" to InputShiftState.SHIFTED_AUTOMATIC.value,
|
||||
"sh:caps_lock" to InputShiftState.CAPS_LOCK.value,
|
||||
),
|
||||
)
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,12 @@ inline fun extCoreTheme(id: String) = ExtensionComponentName(
|
||||
componentId = id,
|
||||
)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun extPreviewTheme(id: String) = ExtensionComponentName(
|
||||
extensionId = "local.themes.preview",
|
||||
componentId = id,
|
||||
)
|
||||
|
||||
interface ThemeExtensionComponent : ExtensionComponent {
|
||||
companion object {
|
||||
fun defaultStylesheetPath(id: String): String {
|
||||
@@ -39,8 +45,6 @@ interface ThemeExtensionComponent : ExtensionComponent {
|
||||
override val label: String
|
||||
override val authors: List<String>
|
||||
val isNightTheme: Boolean
|
||||
val isBorderless: Boolean
|
||||
val isMaterialYouAware: Boolean
|
||||
val stylesheetPath: String?
|
||||
|
||||
fun stylesheetPath(): String = stylesheetPath.takeUnless { it.isNullOrBlank() } ?: defaultStylesheetPath(id)
|
||||
@@ -53,14 +57,12 @@ data class ThemeExtensionComponentImpl(
|
||||
override val authors: List<String>,
|
||||
@SerialName("isNight")
|
||||
override val isNightTheme: Boolean = true,
|
||||
override val isBorderless: Boolean = false,
|
||||
override val isMaterialYouAware: Boolean = false,
|
||||
@SerialName("stylesheet")
|
||||
override val stylesheetPath: String? = null,
|
||||
) : ThemeExtensionComponent {
|
||||
|
||||
fun edit() = ThemeExtensionComponentEditor(
|
||||
id, label, authors, isNightTheme, isBorderless, isMaterialYouAware, stylesheetPath ?: "",
|
||||
id, label, authors, isNightTheme, stylesheetPath ?: "",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,8 +71,6 @@ class ThemeExtensionComponentEditor(
|
||||
override var label: String = "",
|
||||
override var authors: List<String> = emptyList(),
|
||||
override var isNightTheme: Boolean = true,
|
||||
override var isBorderless: Boolean = false,
|
||||
override var isMaterialYouAware: Boolean = false,
|
||||
override var stylesheetPath: String = "",
|
||||
) : ThemeExtensionComponent {
|
||||
|
||||
@@ -83,8 +83,6 @@ class ThemeExtensionComponentEditor(
|
||||
label = label.trim(),
|
||||
authors = authors.filterNot { it.isBlank() },
|
||||
isNightTheme = isNightTheme,
|
||||
isBorderless = isBorderless,
|
||||
isMaterialYouAware = isMaterialYouAware,
|
||||
stylesheetPath = stylesheetPath.takeUnless { it.isBlank() },
|
||||
)
|
||||
check(id.isNotBlank()) { "Theme component ID cannot be blank" }
|
||||
|
||||
@@ -45,7 +45,10 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.appContext
|
||||
import dev.patrickgold.florisboard.extensionManager
|
||||
import dev.patrickgold.florisboard.ime.smartbar.CachedInlineSuggestionsChipStyleSet
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogInfo
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionComponentName
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMeta
|
||||
import dev.patrickgold.florisboard.lib.io.ZipUtils
|
||||
import dev.patrickgold.florisboard.lib.util.ViewUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -54,11 +57,13 @@ import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.florisboard.lib.kotlin.io.FsDir
|
||||
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.snygg.SnyggStylesheet
|
||||
import org.florisboard.lib.snygg.SnyggStylesheetJsonConfig
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.value.MaterialYouColor
|
||||
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
|
||||
import org.florisboard.lib.snygg.value.SnyggStaticColorValue
|
||||
import java.util.UUID
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
@@ -105,9 +110,6 @@ class ThemeManager(context: Context) {
|
||||
prefs.theme.mode.observeForever {
|
||||
updateActiveTheme()
|
||||
}
|
||||
prefs.theme.accentColor.observeForever {
|
||||
updateActiveTheme { MaterialYouColor.updateAccentColor(it) }
|
||||
}
|
||||
prefs.theme.dayThemeId.observeForever {
|
||||
updateActiveTheme()
|
||||
}
|
||||
@@ -122,7 +124,6 @@ class ThemeManager(context: Context) {
|
||||
*/
|
||||
fun updateActiveTheme(action: () -> Unit = { }) = scope.launch {
|
||||
activeThemeGuard.withLock {
|
||||
MaterialYouColor.resetColorSchemeCache()
|
||||
action()
|
||||
previewThemeInfo?.let { previewThemeInfo ->
|
||||
_activeThemeInfo.postValue(previewThemeInfo)
|
||||
@@ -132,25 +133,40 @@ class ThemeManager(context: Context) {
|
||||
val cachedInfo = cachedThemeInfos.find { it.name == activeName }
|
||||
if (cachedInfo != null) {
|
||||
_activeThemeInfo.postValue(cachedInfo)
|
||||
} else {
|
||||
val themeExt = extensionManager.getExtensionById(activeName.extensionId) as? ThemeExtension
|
||||
val themeExtRef = themeExt?.sourceRef
|
||||
if (themeExtRef != null) {
|
||||
val themeConfig = themeExt.themes.find { it.id == activeName.componentId }
|
||||
if (themeConfig != null) {
|
||||
val newStylesheet = ZipUtils.readFileFromArchive(
|
||||
appContext, themeExtRef, themeConfig.stylesheetPath(),
|
||||
).getOrNull()?.let { raw -> SnyggStylesheetJsonConfig.decodeFromString<SnyggStylesheet>(raw) }
|
||||
if (newStylesheet != null) {
|
||||
val newCompiledStylesheet = (newStylesheet)
|
||||
.compileToFullyQualified(FlorisImeUiSpec)
|
||||
val newInfo = ThemeInfo(activeName, themeConfig, newCompiledStylesheet)
|
||||
cachedThemeInfos.add(newInfo)
|
||||
_activeThemeInfo.postValue(newInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
return@withLock
|
||||
}
|
||||
val themeExt = extensionManager.getExtensionById(activeName.extensionId) as? ThemeExtension
|
||||
val themeExtRef = themeExt?.sourceRef
|
||||
if (themeExtRef == null) {
|
||||
return@withLock
|
||||
}
|
||||
val themeConfig = themeExt.themes.find { it.id == activeName.componentId }
|
||||
if (themeConfig == null) {
|
||||
return@withLock
|
||||
}
|
||||
// TODO: loaded dir is implemented already...
|
||||
// TODO: this leaks the loaded dir, but at least the state is not kaputt from compose viewpoint
|
||||
val loadedDir = appContext.cacheDir.subDir("loaded").subDir(UUID.randomUUID().toString())
|
||||
runCatching {
|
||||
loadedDir.mkdirs()
|
||||
loadedDir.deleteContentsRecursively()
|
||||
ZipUtils.unzip(appContext, themeExtRef, loadedDir).getOrThrow()
|
||||
flogInfo { "Loaded extension ${themeExt.meta.id} into $loadedDir" }
|
||||
val stylesheetFile = loadedDir.subFile(themeConfig.stylesheetPath())
|
||||
val stylesheetJson = stylesheetFile.readText()
|
||||
SnyggStylesheet.fromJson(stylesheetJson).getOrThrow()
|
||||
}.fold(
|
||||
onSuccess = { newStylesheet ->
|
||||
val newInfo = ThemeInfo(activeName, themeConfig, newStylesheet, loadedDir, null)
|
||||
cachedThemeInfos.add(newInfo)
|
||||
_activeThemeInfo.postValue(newInfo)
|
||||
},
|
||||
onFailure = { cause ->
|
||||
_activeThemeInfo.postValue(ThemeInfo.DEFAULT.copy(
|
||||
loadFailure = LoadFailure(themeExt.meta, themeConfig, cause)
|
||||
))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,20 +207,16 @@ class ThemeManager(context: Context) {
|
||||
* Creates a new inline suggestion UI bundle based on the attributes of the given [style].
|
||||
*
|
||||
* @param context The context of the parent view/controller.
|
||||
* @param style The theme from which the color attributes should be fetched. Defaults to
|
||||
* [FlorisImeThemeBaseStyle].
|
||||
* @param style The style set which is responsible for styling the chips.
|
||||
*
|
||||
* @return A bundle containing all necessary attributes for the inline suggestion views to properly display.
|
||||
*/
|
||||
@SuppressLint("RestrictedApi")
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
fun createInlineSuggestionUiStyleBundle(
|
||||
context: Context,
|
||||
style: SnyggStylesheet = activeThemeInfo.value?.stylesheet ?: FlorisImeThemeBaseStyle,
|
||||
): Bundle {
|
||||
val snyggStyle = style.getStatic(FlorisImeUi.SmartbarSharedActionsToggle)
|
||||
val bgColor = snyggStyle.background.solidColor(context)
|
||||
val fgColor = snyggStyle.foreground.solidColor(context)
|
||||
fun createInlineSuggestionUiStyleBundle(context: Context): Bundle? {
|
||||
val styleSet = CachedInlineSuggestionsChipStyleSet ?: return null
|
||||
val bgColor = styleSet.background(default = Color.White)
|
||||
val fgColor = styleSet.foreground(default = Color.Black)
|
||||
|
||||
val bgDrawableId = androidx.autofill.R.drawable.autofill_inline_suggestion_chip_background
|
||||
val bgDrawable = Icon.createWithResource(context, bgDrawableId).apply {
|
||||
@@ -279,21 +291,35 @@ class ThemeManager(context: Context) {
|
||||
val name: ExtensionComponentName,
|
||||
val config: ThemeExtensionComponent,
|
||||
val stylesheet: SnyggStylesheet,
|
||||
val loadedDir: FsDir?,
|
||||
val loadFailure: LoadFailure?,
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "ThemeInfo(name=$name, config=$config, loadedDir=$loadedDir)"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT = ThemeInfo(
|
||||
name = extCoreTheme("base"),
|
||||
config = ThemeExtensionComponentImpl(id = "base", label = "Base", authors = listOf()),
|
||||
stylesheet = FlorisImeThemeBaseStyle.compileToFullyQualified(FlorisImeUiSpec),
|
||||
stylesheet = FlorisImeThemeBaseStyle,
|
||||
loadedDir = null,
|
||||
loadFailure = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class LoadFailure(
|
||||
val extension: ExtensionMeta,
|
||||
val component: ThemeExtensionComponent,
|
||||
val cause: Throwable,
|
||||
)
|
||||
|
||||
data class RemoteColors(
|
||||
val packageName: String,
|
||||
val colorPrimary: SnyggSolidColorValue?,
|
||||
val colorPrimaryVariant: SnyggSolidColorValue?,
|
||||
val colorSecondary: SnyggSolidColorValue?,
|
||||
val colorPrimary: SnyggStaticColorValue?,
|
||||
val colorPrimaryVariant: SnyggStaticColorValue?,
|
||||
val colorSecondary: SnyggStaticColorValue?,
|
||||
) {
|
||||
companion object {
|
||||
val DEFAULT = RemoteColors("undefined", null, null, null)
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.florisboard.lib.kotlin.io.readJson
|
||||
import org.florisboard.lib.kotlin.io.subDir
|
||||
import org.florisboard.lib.kotlin.io.subFile
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
class CacheManager(context: Context) {
|
||||
@@ -62,6 +63,8 @@ class CacheManager(context: Context) {
|
||||
private const val ExporterDirName = "exporter"
|
||||
private const val EditorDirName = "editor"
|
||||
private const val BackupAndRestoreDirName = "backup-and-restore"
|
||||
|
||||
const val LoadedDirName = "loaded"
|
||||
}
|
||||
|
||||
private val appContext by context.appContext()
|
||||
|
||||
@@ -16,10 +16,7 @@
|
||||
|
||||
package dev.patrickgold.florisboard.lib.compose
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Button
|
||||
@@ -34,14 +31,11 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun FlorisButton(
|
||||
@@ -166,38 +160,3 @@ fun FlorisIconButton(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FlorisIconButtonWithInnerPadding(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
icon: ImageVector,
|
||||
enabled: Boolean = true,
|
||||
iconModifier: Modifier = Modifier,
|
||||
iconColor: Color = Color.Unspecified,
|
||||
) {
|
||||
IconButton(
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
onClick = onClick,
|
||||
) {
|
||||
val contentAlpha = if (enabled) 1f else 0.14f
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides iconColor,
|
||||
) {
|
||||
Box(
|
||||
modifier = iconModifier
|
||||
.padding(4.dp)
|
||||
.fillMaxHeight()
|
||||
.aspectRatio(1f),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
modifier = modifier.alpha(contentAlpha),
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
||||
//TODO: Use JetPrefDropDownMenu instead
|
||||
@Composable
|
||||
fun <T : Any> FlorisDropdownMenu(
|
||||
items: List<T>,
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.lib.compose
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.ProvideTextStyle
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextDirection
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.lib.ValidationResult
|
||||
|
||||
@Composable
|
||||
fun FlorisOutlinedTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
readOnly: Boolean = false,
|
||||
textStyle: TextStyle = TextStyle.Default,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
placeholder: String? = null,
|
||||
isError: Boolean = false,
|
||||
showValidationHint: Boolean = true,
|
||||
showValidationError: Boolean = false,
|
||||
validationResult: ValidationResult? = null,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
colors: TextFieldColors = OutlinedTextFieldDefaults.colors(),
|
||||
) {
|
||||
var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = value)) }
|
||||
val textFieldValue = textFieldValueState.copy(text = value)
|
||||
|
||||
FlorisOutlinedTextField(
|
||||
value = textFieldValue,
|
||||
onValueChange = {
|
||||
textFieldValueState = it
|
||||
if (value != it.text) {
|
||||
onValueChange(it.text)
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
readOnly = readOnly,
|
||||
textStyle = textStyle,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
singleLine = singleLine,
|
||||
maxLines = maxLines,
|
||||
placeholder = placeholder,
|
||||
isError = isError,
|
||||
showValidationHint = showValidationHint,
|
||||
showValidationError = showValidationError,
|
||||
validationResult = validationResult,
|
||||
visualTransformation = visualTransformation,
|
||||
interactionSource = interactionSource,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FlorisOutlinedTextField(
|
||||
value: TextFieldValue,
|
||||
onValueChange: (TextFieldValue) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
readOnly: Boolean = false,
|
||||
textStyle: TextStyle = TextStyle.Default,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = Int.MAX_VALUE,
|
||||
placeholder: String? = null,
|
||||
isError: Boolean = false,
|
||||
showValidationHint: Boolean = true,
|
||||
showValidationError: Boolean = false,
|
||||
validationResult: ValidationResult? = null,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
colors: TextFieldColors = OutlinedTextFieldDefaults.colors(
|
||||
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
|
||||
disabledBorderColor = MaterialTheme.colorScheme.outline,
|
||||
),
|
||||
) {
|
||||
val textColor = textStyle.color.takeOrElse {
|
||||
if (!enabled) {
|
||||
colors.disabledTextColor
|
||||
} else {
|
||||
colors.unfocusedTextColor
|
||||
}
|
||||
}
|
||||
val mergedTextStyle = textStyle.copy(color = textColor, textDirection = TextDirection.Content)
|
||||
val isFocused by interactionSource.collectIsFocusedAsState()
|
||||
val isErrorState = isError || (showValidationError && validationResult?.isInvalid() == true)
|
||||
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
BasicTextField(
|
||||
modifier = modifier.padding(vertical = 4.dp),
|
||||
value = value,
|
||||
onValueChange = onValueChange,
|
||||
enabled = enabled,
|
||||
readOnly = readOnly,
|
||||
textStyle = mergedTextStyle,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
singleLine = singleLine,
|
||||
maxLines = maxLines,
|
||||
visualTransformation = visualTransformation,
|
||||
cursorBrush = SolidColor(
|
||||
if (isErrorState) {
|
||||
colors.errorCursorColor
|
||||
} else {
|
||||
colors.cursorColor
|
||||
}
|
||||
),
|
||||
decorationBox = { innerTextField ->
|
||||
Surface(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
color = if (enabled) {
|
||||
if (isErrorState) {
|
||||
colors.errorContainerColor
|
||||
} else if (isFocused) {
|
||||
colors.focusedContainerColor
|
||||
} else {
|
||||
colors.unfocusedContainerColor
|
||||
}
|
||||
} else {
|
||||
colors.disabledContainerColor
|
||||
},
|
||||
border = if (isErrorState && enabled) {
|
||||
BorderStroke(ButtonDefaults.outlinedButtonBorder.width, MaterialTheme.colorScheme.error)
|
||||
} else if (isFocused) {
|
||||
BorderStroke(ButtonDefaults.outlinedButtonBorder.width, MaterialTheme.colorScheme.primary)
|
||||
} else {
|
||||
ButtonDefaults.outlinedButtonBorder
|
||||
},
|
||||
shape = shape,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.defaultMinSize(
|
||||
minWidth = ButtonDefaults.MinWidth,
|
||||
minHeight = 40.dp,
|
||||
)
|
||||
.padding(ButtonDefaults.ContentPadding),
|
||||
contentAlignment = Alignment.CenterStart,
|
||||
) {
|
||||
ProvideTextStyle(value = mergedTextStyle) {
|
||||
innerTextField()
|
||||
}
|
||||
if (!placeholder.isNullOrBlank()) {
|
||||
Text(
|
||||
text = placeholder,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.56f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (showValidationHint && validationResult?.isValid() == true && validationResult.hasHintMessage()) {
|
||||
Text(
|
||||
text = validationResult.hintMessage(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.56f),
|
||||
)
|
||||
}
|
||||
|
||||
if (showValidationError && validationResult?.isInvalid() == true && validationResult.hasErrorMessage()) {
|
||||
Text(
|
||||
text = validationResult.errorMessage(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -23,30 +23,22 @@ import android.inputmethodservice.InputMethodService
|
||||
import android.view.Window
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
|
||||
|
||||
@Composable
|
||||
fun SystemUiIme() {
|
||||
val useDarkIcons = !FlorisImeTheme.config.isNightTheme
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
val backgroundColor = FlorisImeTheme.style.get(FlorisImeUi.SystemNavBar).background.solidColor(context)
|
||||
val window = view.context.findWindow()!!
|
||||
val windowInsetsController = WindowInsetsControllerCompat(window, view)
|
||||
|
||||
LaunchedEffect(backgroundColor) {
|
||||
if (AndroidVersion.ATLEAST_API26_O) {
|
||||
window.navigationBarColor = backgroundColor.toArgb()
|
||||
windowInsetsController.isAppearanceLightNavigationBars = useDarkIcons
|
||||
if (AndroidVersion.ATLEAST_API29_Q) window.isNavigationBarContrastEnforced = true
|
||||
LaunchedEffect(useDarkIcons) {
|
||||
windowInsetsController.isAppearanceLightNavigationBars = useDarkIcons
|
||||
if (AndroidVersion.ATLEAST_API29_Q) {
|
||||
window.isNavigationBarContrastEnforced = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.lib.compose
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.lib.ValidationResult
|
||||
|
||||
@Composable
|
||||
fun Validation(
|
||||
showValidationErrors: Boolean,
|
||||
validationResult: ValidationResult?,
|
||||
) {
|
||||
if (showValidationErrors) {
|
||||
if (validationResult is ValidationResult.Valid && validationResult.hasHintMessage()) {
|
||||
Text(
|
||||
text = validationResult.hintMessage(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.56f),
|
||||
)
|
||||
}
|
||||
if (validationResult is ValidationResult.Invalid && validationResult.hasErrorMessage()) {
|
||||
Text(
|
||||
text = validationResult.errorMessage(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,23 +144,22 @@ object ExtensionValidation {
|
||||
val str = input.trim()
|
||||
when {
|
||||
str.isBlank() -> resultInvalid(error = R.string.ext__validation__enter_property)
|
||||
str == "-" || str.startsWith("--") -> resultValid()
|
||||
!SnyggVarValue.VariableNameRegex.matches(str) -> {
|
||||
resultInvalid(error = R.string.ext__validation__error_property, "variable_name_regex" to SnyggVarValue.VariableNameRegex)
|
||||
}
|
||||
else -> resultValid(hint = R.string.ext__validation__hint_property)
|
||||
else -> resultValid()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val SnyggSolidColorValue = ValidationRule<String> {
|
||||
forKlass = org.florisboard.lib.snygg.value.SnyggSolidColorValue::class
|
||||
val SnyggStaticColorValue = ValidationRule<String> {
|
||||
forKlass = org.florisboard.lib.snygg.value.SnyggStaticColorValue::class
|
||||
forProperty = "color"
|
||||
validator { input ->
|
||||
val str = input.trim()
|
||||
when {
|
||||
str.isBlank() -> resultInvalid(error = R.string.ext__validation__enter_color)
|
||||
org.florisboard.lib.snygg.value.SnyggSolidColorValue.deserialize(str).isFailure -> {
|
||||
org.florisboard.lib.snygg.value.SnyggStaticColorValue.deserialize(str).isFailure -> {
|
||||
resultInvalid(error = R.string.ext__validation__error_color)
|
||||
}
|
||||
else -> resultValid()
|
||||
|
||||
@@ -60,7 +60,7 @@ private fun Bundle.debugSummarize(): String {
|
||||
}
|
||||
append(key)
|
||||
append("=")
|
||||
append(bundle.getString(key))
|
||||
// TODO: classcastexception append(bundle.getString(key))
|
||||
}
|
||||
append("]")
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
@@ -12,52 +13,77 @@
|
||||
android:background="@color/colorPrimaryDark"
|
||||
android:elevation="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__description"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_instructions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__report_instructions"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/copy_to_clipboard"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__copy_to_clipboard"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/open_bug_report_form"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__open_issue_tracker"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__description"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stacktrace"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"/>
|
||||
<TextView
|
||||
android:id="@+id/report_instructions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__report_instructions"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/stacktrace"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:id="@+id/footer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__close"/>
|
||||
android:orientation="horizontal"
|
||||
android:padding="2dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/copy_to_clipboard"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__copy_to_clipboard" tools:ignore="ButtonStyle"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/open_bug_report_form"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__open_issue_tracker" tools:ignore="ButtonStyle"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/close_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="2dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp"
|
||||
android:text="@string/crash_dialog__close"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">تحديث الاستراتيجية (مثبت)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">إستراتيجية التحديث (الأخيرة)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">الحد الأقصى للعناصر التي يجب الاحتفاظ بها</string>
|
||||
<string name="prefs__media__emoji_history_pinned_reset">إعادة تعيين الرموز التعبيرية المثبتة</string>
|
||||
<string name="prefs__media__emoji_history_reset">إعادة تعيين الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">اقتراحات الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">تمكين اقتراحات الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">تقديم اقتراحات الرموز التعبيرية أثناء الكتابة</string>
|
||||
@@ -95,6 +97,7 @@
|
||||
<string name="quick_actions_editor__subheader_sticky_action">المهام المثبتة ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">مهام متكيفة ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">مهام مخفية ({n})</string>
|
||||
<string name="select_subtype_panel__header">حدد النوع الفرعي</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">وضع التصفح المتخفي ممكن الآن\n\n{app_name} لن يتعلم الكلمات من مدخلاتك أثناء تنشيط هذا الوضع</string>
|
||||
<string name="incognito_mode__toast_after_disabled">الوضع الخاص هو الان معطل افتراضيا</string>
|
||||
@@ -157,13 +160,11 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">اختيار النمط الليلي</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">تعديل متقدم</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">مستوى التعديل</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">عرض اللون كـ</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">عرض لوحة المفاتيح بعد مربعات الحوار</string>
|
||||
<string name="settings__theme_editor__add_rule">إضافة قاعدة</string>
|
||||
<string name="settings__theme_editor__edit_rule">تحرير القاعدة</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">ورق الأنماط هذا ليس له قواعد محددة. أضف قاعدة لبدء تخصيص ورق الأنماط هذا.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">تم تعريف قاعدة ورقة الأنماط هذه بالفعل.</string>
|
||||
<string name="settings__theme_editor__rule_element">العنصر المستهدف</string>
|
||||
<string name="settings__theme_editor__rule_codes">رموز المفتاح المستهدف</string>
|
||||
<string name="settings__theme_editor__rule_groups">مجموعات</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">حالة زر shift</string>
|
||||
@@ -191,18 +192,11 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">هو نسق ليلي</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">بدون حدود</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">مسار ورقة الأنماط</string>
|
||||
<string name="snygg__rule_element__defines">المتغيرات</string>
|
||||
<string name="snygg__rule_element__defines_description">حدد المتغيرات في هذه القاعدة لإعادة استخدام الألوان أو الأحجام الشائعة في ورقة الأنماط الخاصة بك.</string>
|
||||
<string name="snygg__rule_element__keyboard">نافذة لوحة المفاتيح</string>
|
||||
<string name="snygg__rule_element__key">المفتاح</string>
|
||||
<string name="snygg__rule_element__key_hint">تلميحة المفتاح</string>
|
||||
<string name="snygg__rule_element__key_popup">انبثاق المفتاح</string>
|
||||
<string name="snygg__rule_element__clipboard_header">رأس الحافظة</string>
|
||||
<string name="snygg__rule_element__clipboard_item">عنصر الحافظة</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">عنصر الحافظة المنبثق</string>
|
||||
<string name="snygg__rule_element__emoji_key">مفتاح الرموز التعبيرية</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">انبثاق مفتاح الرموز التعبيرية</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">تبويب الرموز التعبيرية</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">هيئة شكل الإدخال الأفقي</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">حقل الإدخال الأفقي</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">مهام الإدخال الأفقي</string>
|
||||
@@ -225,12 +219,9 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">مرشح كلمة الشريط الذكي</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">مرشح مقطع الشريط الذكي</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">مرشح فاصل الشريط الذكي</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">شريط تنقل النظام</string>
|
||||
<string name="snygg__rule_selector__pressed">مضغوط</string>
|
||||
<string name="snygg__rule_selector__focus">تركيز</string>
|
||||
<string name="snygg__rule_selector__disabled">معطّل</string>
|
||||
<string name="snygg__property_name__width">العرض</string>
|
||||
<string name="snygg__property_name__height">الارتفاع</string>
|
||||
<string name="snygg__property_name__background">الخلفية</string>
|
||||
<string name="snygg__property_name__foreground">المقدمة</string>
|
||||
<string name="snygg__property_name__border_color">لون الحدود</string>
|
||||
@@ -239,7 +230,6 @@
|
||||
<string name="snygg__property_name__font_family">عائلة الخط</string>
|
||||
<string name="snygg__property_name__font_size">حجم الخط</string>
|
||||
<string name="snygg__property_name__font_style">نوع الخط</string>
|
||||
<string name="snygg__property_name__font_variant">متغير الخط</string>
|
||||
<string name="snygg__property_name__font_weight">ثقل الخط</string>
|
||||
<string name="snygg__property_name__shadow_elevation">ارتفاع الظل</string>
|
||||
<string name="snygg__property_name__shape">الشكل</string>
|
||||
@@ -258,10 +248,10 @@
|
||||
<string name="snygg__property_name__var_shape">شكل مشترك</string>
|
||||
<string name="snygg__property_name__var_shape_variant">الشكل المشترك (متغير)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">موروث</string>
|
||||
<string name="snygg__property_value__defined_var">مرجع Var</string>
|
||||
<string name="snygg__property_value__solid_color">لون كامل</string>
|
||||
<string name="snygg__property_value__material_you_light_color">تصميم المواد الخاص بك (مضيء)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">تصميم المواد الخاص بك (داكن)</string>
|
||||
<string name="snygg__property_value__image_ref">مرجع الصورة</string>
|
||||
<string name="snygg__property_value__rectangle_shape">شكل مستطيل</string>
|
||||
<string name="snygg__property_value__circle_shape">شكل الدائرة</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">شكل مقصوص الحواف (dp)</string>
|
||||
@@ -271,7 +261,6 @@
|
||||
<string name="snygg__property_value__dp_size">الحجم (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">الحجم (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">الحجم (%)</string>
|
||||
<string name="snygg__property_value__defined_var">مرجع Var</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">الصوت والاهتزاز</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">ردود الفعل الصوتية / الأصوات</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">تمكين التاثيرات الصوتية</string>
|
||||
@@ -346,11 +335,8 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">عرض الإقراحات أثناء الكتابة</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">وضع عرض الإقتراحات</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">حجب الكلمات التي من المحتمل كونها مسيئة</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">إقتراحات محتوى الحافظة</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">اقتراح المحتويات المنسوخة في سجل الحافظة</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">تحديد حجم مخصص لاقتراحات الحافظة إلى</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">العناصر التي تم نسخها خلال آخر {v}</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">إظهار الاقتراحات المضمنة التي تقدمها خدمات الملء التلقائي</string>
|
||||
<string name="pref__suggestion__incognito_mode__label" comment="Label of Incognito mode preference in Typing">الوضع المخفي</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">التصحيحات</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">استخدام الأحرف الكبيرة تلقائيًا</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">استخدام الأحرف الكبيرة في الكلمات على حسب سياق نص الإدخال الحالي</string>
|
||||
@@ -424,16 +410,16 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">الضغطة المطولة لمفتاح الحذف</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">عتبة سرعة السحب</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">عتبة مسافة السحب</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">إعدادات متقدمة</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">إعدادات المظهر</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">افتراضي النظام (أموليد)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">فاتح</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">داكن</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">أسود قاتم</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">إعدادات اللغة</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">إظهار أيقونة البرنامج في درج التطبيقات</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">ممكّن دائمًا على اندرويد 10+ فما فوق بسبب قيود النظام</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">الوضع المخفي</string>
|
||||
<string name="settings__other__title" comment="Title of Other settings">أخرى</string>
|
||||
<string name="pref__other__settings_theme__label" comment="Label of Settings theme preference in Other">إعدادات المظهر</string>
|
||||
<string name="pref__other__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Other">افتراضي النظام (أموليد)</string>
|
||||
<string name="pref__other__settings_theme__light" comment="Possible value of Settings theme preference in Other">فاتح</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">داكن</string>
|
||||
<string name="pref__other__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Other">أسود قاتم</string>
|
||||
<string name="pref__other__settings_accent_color__label" comment="Label of accent color preference in Other">اللون الثانوي للإعدادات </string>
|
||||
<string name="pref__other__settings_language__label" comment="Label of Settings language preference in Other">إعدادات اللغة</string>
|
||||
<string name="pref__other__show_app_icon__label" comment="Label of Show app icon preference in Other">إظهار أيقونة البرنامج في درج التطبيقات</string>
|
||||
<string name="pref__other__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Other for Android 10+">ممكّن دائمًا على اندرويد 10+ فما فوق بسبب قيود النظام</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">حول التطبيق</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">أيقونة التطبيق FlorisBoard</string>
|
||||
@@ -554,6 +540,11 @@
|
||||
<string name="pref__clipboard__sync_from_system_clipboard__summary">عند مزامنة حافظة النظام يتم مزامنة حافظة لوحة المفاتيح تلقائيا</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__label">مزامنة الى حافظة النظام</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__summary">تحديثات حافظة لوحة المفاتيح يقوم أيضًا بتحديث حافظة النظام</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">إقتراحات الحافظة</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__label" comment="Preference title">إقتراحات محتوى الحافظة</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__summary" comment="Preference summary">اقتراح المحتويات المنسوخة في سجل الحافظة</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__summary` and is the first part">تحديد حجم مخصص لاقتراحات الحافظة إلى</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__label` and is the second part">العناصر التي تم نسخها خلال آخر {v}</string>
|
||||
<string name="pref__clipboard__group_clipboard_history__label">سجل الحافظة</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__label">تمكين سجل الحافظة</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">الاحتفاظ بعناصر الحافظة للوصول السريع</string>
|
||||
@@ -673,7 +664,6 @@
|
||||
<string name="ext__validation__error_stylesheet_path">يرجى إدخال مسار ورقة أنماط صالح يطابق {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">يرجى إدخال اسم المتغير</string>
|
||||
<string name="ext__validation__error_property">يرجى إدخال اسم متغير صالح يطابق {variable_name_regex}</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">حسب الاتفاقية، يبدأ اسم متغير FlorisCSS بشرطتين (--)</string>
|
||||
<string name="ext__validation__enter_color">يرجى إدخال سلسلة ألوان</string>
|
||||
<string name="ext__validation__error_color">يرجى إدخال سلسلة ألوان صالحة</string>
|
||||
<string name="ext__validation__enter_dp_size">يرجى إدخال حجم dp</string>
|
||||
@@ -702,6 +692,8 @@
|
||||
<string name="action__delete">حذف</string>
|
||||
<string name="action__delete_confirm_title">تأكيد الحذف</string>
|
||||
<string name="action__delete_confirm_message">هل أنت متأكد من حذف \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء بمجرد تنفيذه.</string>
|
||||
<string name="action__reset_confirm_title">تأكيد إعادة التعيين</string>
|
||||
<string name="action__reset_confirm_message">هل أنت متأكد من أعادة تعيين \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء بمجرد تنفيذه.</string>
|
||||
<string name="action__discard">تجاهل</string>
|
||||
<string name="action__discard_confirm_title">تغييرات غير محفوظة</string>
|
||||
<string name="action__discard_confirm_message">هل أنت متأكد أنك تريد تجاهل التغييرات غير المحفوظة؟ لا يمكن التراجع عن هذا الإجراء بمجرد تنفيذه.</string>
|
||||
@@ -747,8 +739,6 @@
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">عرض ديناميكي & قابل للسحب</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_double_tap" comment="Enum value label">تمكين مفتاح Caps Lock من خلال النقر المزدوج على Shift</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_cycle" comment="Enum value label">قم بالتبديل إلى خطوة الكتابة بالأحرف الكبيرة التالية في كل مرة يتم فيها الضغط على مفتاح Shift</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">سداسي عشري</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">أحمر أخضر أزرق الشفافية</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">الإظهار دائماً</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">اعرض لوحة المفاتيح دائمًا بعد إغلاق أي محرر حوار</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">لا تُظهر أبداً</string>
|
||||
@@ -817,7 +807,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">لا تُظهر أبداً</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">الإظهار دائماً</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">يعين بشكل ديناميكي</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">إيقاف</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">وضع اليد اليسرى</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">وضع اليد اليمنى</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">بداية علوية</string>
|
||||
|
||||
@@ -89,17 +89,13 @@
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Almacenamientu internu</string>
|
||||
<string name="pref__theme__source_external" comment="Label for the theme source field">Fornidor esternu</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Esta fueya d\'estilu nun tien nenguna regla definida. Amiesta una regla pa comenzar a personalizar la fueya d\'estilu.</string>
|
||||
<string name="settings__theme_editor__rule_element">Elementu de destín</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grupos</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selectores</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Aplica la regla a tolos elementos de destín.</string>
|
||||
<string name="snygg__rule_element__defines">Variables</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Distribución d\'entrada n\'horizontal</string>
|
||||
<string name="snygg__rule_element__smartbar">Barra intelixente</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_toggle">Alternador de les aiciones compartíes de la barra intelixente</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_toggle">Alternador de les aiciones estendíes de la barra intelixente</string>
|
||||
<string name="snygg__property_name__width">Llargor</string>
|
||||
<string name="snygg__property_name__height">Altor</string>
|
||||
<string name="snygg__property_name__shape">Forma</string>
|
||||
<string name="snygg__property_name__var_primary">Color primariu</string>
|
||||
<string name="snygg__property_name__var_secondary">Color secundariu</string>
|
||||
@@ -135,10 +131,6 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Forne suxerencies mentanto teclexes</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Mou de l\'apaición de les suxerencies</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Bloquiar les pallabres ofensives</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Suxerencies del conteníu del cartafueyu</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Suxer el conteníu del cartafueyu copiáu anteriormente</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Llendar les suxerencies del cartafueyu a</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">los elementos copiaos nos últimos {v} s</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Correiciones</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Mayúscules automátiques</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Pon en mayúscula la primer lletra de les pallabres según el contestu de la entrada actual</string>
|
||||
@@ -157,10 +149,6 @@
|
||||
<string name="pref__glide__enabled__label" comment="Preference title">Activar la escritura eslizante</string>
|
||||
<string name="pref__gestures__general_title" comment="Preference group title">Xestos en xeneral</string>
|
||||
<string name="pref__gestures__space_bar_title" comment="Preference group title">Xestos de la barra d\'espaciu</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Configuración avanzada</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Estilu de la configuración</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Llingua de la configuración</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Amosar l\'iconu l\'aplicación nel llanzador</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__view_licenses" comment="Label of View licenses button in About">Llicencies de códigu abiertu</string>
|
||||
<string name="about__view_privacy_policy" comment="Label of View privacy policy button in About">Política de privacidá</string>
|
||||
@@ -225,6 +213,7 @@
|
||||
<string name="settings__clipboard__title">Cartafueyu</string>
|
||||
<string name="pref__clipboard__use_internal_clipboard__label">Usar el cartafueyu internu</string>
|
||||
<string name="pref__clipboard__use_internal_clipboard__summary">Usa un cartafueyu internu en cuentes del que tien sistema</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">Suxerencies del cartafueyu</string>
|
||||
<string name="send_to_clipboard__unknown_error">Prodúxose un error desconocíu. ¡Volvi tentalo!</string>
|
||||
<string name="send_to_clipboard__type_not_supported_error">Esti elementu multimedia nun ye compatible.</string>
|
||||
<!-- Devtools strings -->
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<string name="quick_actions_editor__subheader_sticky_action">Винаги видимо действие ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Динамично показвани действия ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Скрити действия ({n})</string>
|
||||
<string name="select_subtype_panel__header">Изберете подвид</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">Режимът инкогнито е включен\n\n{app_name} няма да запомня нещата, които въвеждате докато този режим е включен</string>
|
||||
<string name="incognito_mode__toast_after_disabled">Режимът инкогнито е изключен по подразбиране</string>
|
||||
@@ -111,6 +112,7 @@
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">Клавиатурата FlorisBoard не е избрана като подразбиран метод за въвеждане. Докоснете, за да направите промяната.</string>
|
||||
<string name="settings__localization__title" comment="Title of languages and Layout screen">Езици и подредби</string>
|
||||
<string name="settings__localization__display_language_names_in__label" comment="Label of Display language names in preference">Изписване на езиците на</string>
|
||||
<string name="settings__localization__display_keyboard_labels_in_subtype_language" comment="Label of Display keyboard labels in subtype language preference">Етикети на клавиатурата на езика на подредбата</string>
|
||||
<string name="settings__localization__group_subtypes__label" comment="Label of subtypes group">Подредби</string>
|
||||
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">Добавяне на подредба</string>
|
||||
<string name="settings__localization__language_pack_title" comment="Title of the language pack manager screen for managing installed and custom language packs">Управление на инсталираните езикови пакети</string>
|
||||
@@ -151,7 +153,6 @@
|
||||
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Време на залез</string>
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Дневна тема</string>
|
||||
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Нощна тема</string>
|
||||
<string name="pref__theme__theme_accent_color__label" comment="Label of accent color preference in Theme">Допълнителен цвят (за теми на Material you)</string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Управление на теми</string>
|
||||
<string name="pref__theme__source_assets" comment="Label for the theme source field">Активи на FlorisBoard</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Вътрешно хранилище</string>
|
||||
@@ -160,13 +161,11 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Избор на нощна тема</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">Настройки на редактора</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">Режим</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Формат на цветовете</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Видима клавиатура след диалог</string>
|
||||
<string name="settings__theme_editor__add_rule">Добавяне на правило</string>
|
||||
<string name="settings__theme_editor__edit_rule">Променяне на правило</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Стиловият лист няма правила. За да промените стиловете добавете правила.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Вече има такова правило.</string>
|
||||
<string name="settings__theme_editor__rule_element">Целеви елемент</string>
|
||||
<string name="settings__theme_editor__rule_codes">Целеви кодове</string>
|
||||
<string name="settings__theme_editor__rule_groups">Групи</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Състояние на Shift</string>
|
||||
@@ -194,18 +193,11 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">Нощна тема</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">Без кант</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">Път към стиловия лист</string>
|
||||
<string name="snygg__rule_element__defines">Променливи</string>
|
||||
<string name="snygg__rule_element__defines_description">Създайте променливи в това правило, за да използвате общи цветове или размери в стиловия лист.</string>
|
||||
<string name="snygg__rule_element__keyboard">Прозорец на клавиатурата</string>
|
||||
<string name="snygg__rule_element__key">Клавиш</string>
|
||||
<string name="snygg__rule_element__key_hint">Горен индекс на клавиш</string>
|
||||
<string name="snygg__rule_element__key_popup">Подсказка на клавиш</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Заглавка на междинната памет</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Елемент от междинната памет</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Подсказка на елемент от междинната памет</string>
|
||||
<string name="snygg__rule_element__emoji_key">Клавиш за емоции</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">Подсказка на клавиша за емоции</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Раздел с емоции</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Пейзажен изглед за въвеждане</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Пейзажно поле за въвеждане</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Действие на пейзажно поле за въвеждане</string>
|
||||
@@ -228,12 +220,9 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Интелигентна лента, кандидат за дума</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Интелигентна лента, контейнер с кандидати</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">Интелигентна лента, разделител на кандидати</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Интелигентна лента, лента за навигация</string>
|
||||
<string name="snygg__rule_selector__pressed">Натиснат</string>
|
||||
<string name="snygg__rule_selector__focus">На фокус</string>
|
||||
<string name="snygg__rule_selector__disabled">Изключен</string>
|
||||
<string name="snygg__property_name__width">Ширина</string>
|
||||
<string name="snygg__property_name__height">Височина</string>
|
||||
<string name="snygg__property_name__background">Фон</string>
|
||||
<string name="snygg__property_name__foreground">Преден план</string>
|
||||
<string name="snygg__property_name__border_color">Цвят на канта</string>
|
||||
@@ -242,7 +231,6 @@
|
||||
<string name="snygg__property_name__font_family">Семейство на шрифта</string>
|
||||
<string name="snygg__property_name__font_size">Размер на шрифта</string>
|
||||
<string name="snygg__property_name__font_style">Стил на шрифта</string>
|
||||
<string name="snygg__property_name__font_variant">Вариант на шрифта</string>
|
||||
<string name="snygg__property_name__font_weight">Тежест на шрифта</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Големина на сянката</string>
|
||||
<string name="snygg__property_name__shape">Форма</string>
|
||||
@@ -261,10 +249,10 @@
|
||||
<string name="snygg__property_name__var_shape">Обща форма</string>
|
||||
<string name="snygg__property_name__var_shape_variant">Обща форма (вариант)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">Наследяване</string>
|
||||
<string name="snygg__property_value__defined_var">От променлива</string>
|
||||
<string name="snygg__property_value__solid_color">Плътен цвят</string>
|
||||
<string name="snygg__property_value__material_you_light_color">Цвят на Material You (светъл)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">Цвят на Material You (тъмен)</string>
|
||||
<string name="snygg__property_value__image_ref">От изображение</string>
|
||||
<string name="snygg__property_value__rectangle_shape">Правоъгълна форма</string>
|
||||
<string name="snygg__property_value__circle_shape">Кръгла форма</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">Форма с рязани ъгли (dp)</string>
|
||||
@@ -274,7 +262,6 @@
|
||||
<string name="snygg__property_value__dp_size">Размер (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">Размер (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">Размер (%)</string>
|
||||
<string name="snygg__property_value__defined_var">От променлива</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Звук и вибрация</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Звукова обратна връзка / звуци</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Звукова обратна връзка</string>
|
||||
@@ -349,11 +336,8 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Показва предложения докато въвеждате</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Оформление на предложенията</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Спиране на предполагаемо обидни думи</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Предложения от междинната памет</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Предлага вече копирано съдържание</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Ограничаване на предложенията от временната памет до</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">Елементите, копирани последните {v} сек.</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">Показване на предложения от услугите за автоматично попълване</string>
|
||||
<string name="pref__suggestion__incognito_mode__label" comment="Label of Incognito mode preference in Typing">Поверителен режим</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Корекции</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Автоматично въвеждане на главни букви</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Използват се главни букви въз основа на контекста на въвеждане</string>
|
||||
@@ -427,17 +411,16 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Задържане на клавиш „изтриване“</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Праг за скоростта на плъзгане</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Минимално разстояние на плъзване</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Разширени</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Тема на настройките</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Според системата (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Светла</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Тъмна</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">Тъмна AMOLED</string>
|
||||
<string name="pref__advanced__settings_accent_color__label" comment="Label of accent color preference in Advanced">Допълнителен цвят на настройките</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Език на настройките</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Икона на приложението в стартовия панел</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Винаги видима за Android 10+ поради ограничения на системата</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">Поверителен режим</string>
|
||||
<string name="settings__other__title" comment="Title of Other settings">Други</string>
|
||||
<string name="pref__other__settings_theme__label" comment="Label of Settings theme preference in Other">Тема на настройките</string>
|
||||
<string name="pref__other__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Other">Според системата (AMOLED)</string>
|
||||
<string name="pref__other__settings_theme__light" comment="Possible value of Settings theme preference in Other">Светла</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">Тъмна</string>
|
||||
<string name="pref__other__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Other">Тъмна AMOLED</string>
|
||||
<string name="pref__other__settings_accent_color__label" comment="Label of accent color preference in Other">Допълнителен цвят на настройките</string>
|
||||
<string name="pref__other__settings_language__label" comment="Label of Settings language preference in Other">Език на настройките</string>
|
||||
<string name="pref__other__show_app_icon__label" comment="Label of Show app icon preference in Other">Пиктограма на приложението на началния екран</string>
|
||||
<string name="pref__other__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Other for Android 10+">Винаги видима за Android 10+ поради ограничения на системата</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Относно</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Икона на приложението FlorisBoard</string>
|
||||
@@ -557,6 +540,11 @@
|
||||
<string name="pref__clipboard__sync_from_system_clipboard__summary">Промените в системната памет се отразяват в тази на приложението</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__label">Изнасяне в системната междинна памет</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__summary">Промените в междинната памет на приложението се отразяват и в системната</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">Предложения от междинната памет</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__label" comment="Preference title">Предложения от съдържанието на междинната памет</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__summary" comment="Preference summary">Предлага вече копирано съдържание</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__summary` and is the first part">Ограничаване на предложенията от междинната памет до</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__label` and is the second part">Елементи, копирани през последните {v} секунди</string>
|
||||
<string name="pref__clipboard__group_clipboard_history__label">История на междинната памет</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__label">История</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">Запазване на копираното за по-бърз достъп до него</string>
|
||||
@@ -676,7 +664,6 @@
|
||||
<string name="ext__validation__error_stylesheet_path">Въведете път към стилов лист, удовлетворяващ регулярния израз {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Въведете име на променливата</string>
|
||||
<string name="ext__validation__error_property">Въведете име на променлива, удовлетворяващо регулярния израз {variable_name_regex}</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">По правило имената на променливите на FlorisCSS започват с две тирета (--)</string>
|
||||
<string name="ext__validation__enter_color">Въведете низ на цвят</string>
|
||||
<string name="ext__validation__error_color">Въведете низ на съществуващ цвят</string>
|
||||
<string name="ext__validation__enter_dp_size">Въведете размер на dp</string>
|
||||
@@ -752,8 +739,6 @@
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">Динамична ширина с плъзгач</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_double_tap" comment="Enum value label">Само главни букви при двойно докосване на клавиша Shift</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_cycle" comment="Enum value label">Превключва способите за въвеждане на главни букви при всяко докосване на Shift</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">Шестнадесетичен</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">Червено, зелено, синьо, прозрачност</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">Винаги се показва</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">Клавиатурата се показва винаги след затваряне на диалог</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">Никога не се показва</string>
|
||||
@@ -822,7 +807,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Не се показва</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Винаги се показва</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Показва се динамично</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Изключено</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">За лява ръка</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">За дясна ръка</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Горе, начало</string>
|
||||
|
||||
@@ -51,10 +51,6 @@
|
||||
<string name="pref__gestures__general_title" comment="Preference group title">Generalne gestikulacije</string>
|
||||
<string name="pref__gestures__space_bar_title" comment="Preference group title">Gestikulacije na razmaknici</string>
|
||||
<string name="pref__gestures__swipe_right__label" comment="Preference title">Prevuci desno</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Napredno</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Tema za podešavanja</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Svijetlo</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Tamno</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Informacije o...</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Ikonica FlorisBoard aplikacije</string>
|
||||
@@ -79,7 +75,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Nikad ne prikaži</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Uvijek prikaži</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Prikaži dinamički</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Isključeno</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Mod za lijevu ruku</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Mod za desnu ruku</string>
|
||||
<string name="enum__swipe_action__no_action" comment="Enum value label">Bez akcije</string>
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
<string name="pref__theme__source_external" comment="Label for the theme source field">Proveïdor extern</string>
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">Selecciona el tema del dia</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Selecciona el tema de nit</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Mostrar els colors com</string>
|
||||
<string name="settings__theme_editor__add_rule">Afegir norma</string>
|
||||
<string name="settings__theme_editor__edit_rule">Editar norma</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grups</string>
|
||||
@@ -94,8 +93,6 @@
|
||||
<string name="snygg__rule_selector__pressed">Premut</string>
|
||||
<string name="snygg__rule_selector__focus">Enfocat</string>
|
||||
<string name="snygg__rule_selector__disabled">Desactivat</string>
|
||||
<string name="snygg__property_name__width">Amplada</string>
|
||||
<string name="snygg__property_name__height">Altura</string>
|
||||
<string name="snygg__property_name__background">Fons</string>
|
||||
<string name="snygg__property_name__foreground">Primer pla</string>
|
||||
<string name="snygg__property_name__border_color">Color dels marges</string>
|
||||
@@ -173,7 +170,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">No mostrar mai</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Mostrar sempre</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Mostrar dinàmicament</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Desactivat</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Mode esquerrà</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Mode dretà</string>
|
||||
<string name="enum__swipe_action__hide_keyboard" comment="Enum value label">Amagar el teclat</string>
|
||||
|
||||
@@ -133,13 +133,11 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">ڕووکارەکانی دۆخی تاریک</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">گۆڕینی ڕەنگ</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">ئاستی دەستکاریکردن</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">پیشاندانی ڕەنگەکان بەشێوەی</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">پیشاندانی تەختەکلیل دوای دەستکاریکردن</string>
|
||||
<string name="settings__theme_editor__add_rule">زیادکردن</string>
|
||||
<string name="settings__theme_editor__edit_rule">دەستکاریکردن</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">ئەم پەڕەیە هیچ یاسایەکی پێناسە نەکراوە، زیادکردنی یاسایەک بۆ دەستکردن بە سازکردنی ئەم پەڕەیە.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">ئەم یاسای پەڕەی ستایڵ پێشتر پێناسە کراوە.</string>
|
||||
<string name="settings__theme_editor__rule_element">بەشی مەبەست</string>
|
||||
<string name="settings__theme_editor__rule_codes">سەرچاوەی کۆدی مەبەست</string>
|
||||
<string name="settings__theme_editor__rule_groups">گرووپ</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">دۆخی شێفت</string>
|
||||
@@ -167,18 +165,11 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">ڕووکاری تاریکە</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">بێ لێوار</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">شوێنی هەڵگرتن</string>
|
||||
<string name="snygg__rule_element__defines">گۆڕاو</string>
|
||||
<string name="snygg__rule_element__defines_description">پێناسەکردنی گۆڕاوەکان لەناو ئەم یاسایە بۆ دووبارە بەکارهێنانی ڕەنگەکان یان قەبارە باوەکان لە پەڕەی ستایڵەکەت.</string>
|
||||
<string name="snygg__rule_element__keyboard">پشتەوەی تەختەکلیل</string>
|
||||
<string name="snygg__rule_element__key">دوگمە</string>
|
||||
<string name="snygg__rule_element__key_hint">پیتە لاوەکییەکان</string>
|
||||
<string name="snygg__rule_element__key_popup">بچووککراوەی پیت</string>
|
||||
<string name="snygg__rule_element__clipboard_header">سەرەوەی لەبەرگیراوەکان</string>
|
||||
<string name="snygg__rule_element__clipboard_item">لەبەرگیراوەکان</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">فرمانەکانی لەبەرگیراوەکان</string>
|
||||
<string name="snygg__rule_element__emoji_key">دوگمەی خەندەکان</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">دوگمەی خەندەکان لاوەکی</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">بەشی خەندەکان</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">دۆخی ئاسۆیی</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">دۆخی ئاسۆیی</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">فرمانی دۆخی ئاسۆیی</string>
|
||||
@@ -195,12 +186,9 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">ڕەنگی نووسینەکانی بەشی ئامراز</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">ڕەنگی ئایکۆنەکانی ئامراز</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">ماوەی نێوان ئامرازەکان</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">ڕەنگی بەشی خوراەوە</string>
|
||||
<string name="snygg__rule_selector__pressed">دەسلێدان</string>
|
||||
<string name="snygg__rule_selector__focus">دەست ڕاگرتن</string>
|
||||
<string name="snygg__rule_selector__disabled">نا چالاک</string>
|
||||
<string name="snygg__property_name__width">پانی</string>
|
||||
<string name="snygg__property_name__height">بەرزی</string>
|
||||
<string name="snygg__property_name__background">پشت شاشە</string>
|
||||
<string name="snygg__property_name__foreground">شاشەی لاوەکی</string>
|
||||
<string name="snygg__property_name__border_color">ڕەنگی لێوار</string>
|
||||
@@ -209,7 +197,6 @@
|
||||
<string name="snygg__property_name__font_family">شێوازی فۆنت</string>
|
||||
<string name="snygg__property_name__font_size">قەبارەی فۆنت</string>
|
||||
<string name="snygg__property_name__font_style">شێوەی فۆنت</string>
|
||||
<string name="snygg__property_name__font_variant">جۆری فۆنت</string>
|
||||
<string name="snygg__property_name__font_weight">شێوەی فۆنت</string>
|
||||
<string name="snygg__property_name__shadow_elevation">شکانەوەی سێبەر</string>
|
||||
<string name="snygg__property_name__shape">شێوە</string>
|
||||
@@ -228,8 +215,8 @@
|
||||
<string name="snygg__property_name__var_shape">شێوەی دوگمەکان</string>
|
||||
<string name="snygg__property_name__var_shape_variant">شێوەی دوگمەکان (هەمەجۆر)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">بنەڕەتی</string>
|
||||
<string name="snygg__property_value__defined_var">سەرچاوە</string>
|
||||
<string name="snygg__property_value__solid_color">ڕەنگ</string>
|
||||
<string name="snygg__property_value__image_ref">وێنە</string>
|
||||
<string name="snygg__property_value__rectangle_shape">چوارگۆشەیی</string>
|
||||
<string name="snygg__property_value__circle_shape">بازنەیی</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">گۆشە چوارگۆشەیی (dp)</string>
|
||||
@@ -239,7 +226,6 @@
|
||||
<string name="snygg__property_value__dp_size">قەبارە (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">قەبارە (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">قەبارە (٪)</string>
|
||||
<string name="snygg__property_value__defined_var">سەرچاوە</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">ڕێکخستنی دەنگ و لەرزین</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">کاریگەری دەنگ / دەستلێدان</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">چالاککردنی کاریگەری دەنگی</string>
|
||||
@@ -307,10 +293,6 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">پیشاندانی ووشە پێشنیارکراوەکان لەکاتی نووسیندا</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">شێوەی دەرکەوتنی پێشنیارەکان</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">ڕێگریکردن لە ووشەی نابەجێ</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">پێشنیارکردنی شتە کۆپیکراوەکان</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">شاردنەوە و ڕێگریکردن لە ووشەکانی جنێودان وتەی ناشرین و نابەجێ</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">ماوەی پیشاندانی لەبەرگیراوەکان</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">ماوەی پیشاندان {v} چرکە</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">پیشاندانی پێشنیاری تەواوکەری خۆکاری </string>
|
||||
<string name="pref__correction__title" comment="Preference group title">ڕاستکردنەوە</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">گەورەکردنی خۆکاری</string>
|
||||
@@ -385,16 +367,6 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">دوگمەی سڕینەوە لەکاتی دەست ڕاگرتن</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">ئاستی خێرایی ڕاکێشان</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">ماوەی ڕاکێشان</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">ڕێکخستنی زیاتر</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">ڕووکاری بەرنامەکە</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">بەپێی سیستەم (ئەمۆلید)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">ڕووناک</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">تاریک</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">ڕەشی ئەمۆلید</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">زمانی بەرنامە</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">پیشاندانی ئایکۆنی بەرنامەکە</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">هەمیشە پیشان ئەدرێ لە ئەندرۆیدی 10 بەرەوسەر</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">دۆخی نادیار</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">دەربارە</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">پیشاندانی ئایکۆنی بەرنامەکە</string>
|
||||
@@ -646,8 +618,6 @@
|
||||
<string name="enum__candidates_display_mode__classic" comment="Enum value label">ئاسایی (٣ ڕیز)</string>
|
||||
<string name="enum__candidates_display_mode__dynamic" comment="Enum value label">جوڵاو</string>
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">جوڵاو و ڕاکێشان</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">ژمارەیی</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">سوور سەوز شین</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">هەمیشە پیشاندان</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">پیشاندانی تەختەکلیل دوای داخستنی بەشی دەستکاریکردنی ڕووکار</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">پیشان نەدان</string>
|
||||
@@ -690,7 +660,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">شاردنەوە</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">هەمیشە پیشاندان</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">پیشاندانی زیرەکانە</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">نا چالاک</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">بەکارهێنان بۆ دەستی چەپ</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">بەکارهێنان بۆ دەستی ڕاست</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">سەرەتای سەرەوە</string>
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<string name="quick_actions_editor__subheader_sticky_action">Připnutá akce ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Dynamické akce ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Skrýt akce ({n})</string>
|
||||
<string name="select_subtype_panel__header">Vyberte podtyp</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">Anonymní režim je nyní povolen\n\nV tomto režimu se {app_name} nebude učit slova z vašeho zadávání</string>
|
||||
<string name="incognito_mode__toast_after_disabled">Anonymní režim je nyní ve výchozím nastavení zakázán</string>
|
||||
@@ -111,6 +112,7 @@
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">FlorisBoard není vybrán jako výchozí vstupní metoda. Kliknutím sem tento problém vyřešíte.</string>
|
||||
<string name="settings__localization__title" comment="Title of languages and Layout screen">Jazyky a rozložení</string>
|
||||
<string name="settings__localization__display_language_names_in__label" comment="Label of Display language names in preference">Zobrazovat názvy jazyků v</string>
|
||||
<string name="settings__localization__display_keyboard_labels_in_subtype_language" comment="Label of Display keyboard labels in subtype language preference">Zobrazit popisky kláves v jazyce podtypu</string>
|
||||
<string name="settings__localization__group_subtypes__label" comment="Label of subtypes group">Podtypy</string>
|
||||
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">Přidat podtyp</string>
|
||||
<string name="settings__localization__language_pack_title" comment="Title of the language pack manager screen for managing installed and custom language packs">Spravovat nainstalované jazykové balíčky</string>
|
||||
@@ -151,8 +153,6 @@
|
||||
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Čas západu slunce</string>
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Denní motiv</string>
|
||||
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Noční motiv</string>
|
||||
<string name="pref__theme__theme_accent_color__label" comment="Label of accent color preference in Theme"> Barva (motivy Material You)
|
||||
</string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Spravovat nainstalované motivy</string>
|
||||
<string name="pref__theme__source_assets" comment="Label for the theme source field">Podklady aplikace FlorisBoard</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Interní úložiště</string>
|
||||
@@ -161,13 +161,11 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Vyberte noční motiv</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">Jemné doladění editoru</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">Úprava úrovně</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Zobrazit barvy jako</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Zobrazit klávesnici po dialozích</string>
|
||||
<string name="settings__theme_editor__add_rule">Přidat pravidlo</string>
|
||||
<string name="settings__theme_editor__edit_rule">Upravit pravidlo</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Tato tabulka stylů nemá definována žádná pravidla. Přidejte pravidlo, abyste mohli začít přizpůsobovat tuto tabulku.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Pravidlo této tabulky stylů je již definováno.</string>
|
||||
<string name="settings__theme_editor__rule_element">Cílový prvek</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kódy cílových kláves</string>
|
||||
<string name="settings__theme_editor__rule_groups">Skupiny</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Stavy shiftu</string>
|
||||
@@ -195,18 +193,11 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">Noční motiv</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">Bez okrajů</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">Cesta tabulky stylů</string>
|
||||
<string name="snygg__rule_element__defines">Proměnné</string>
|
||||
<string name="snygg__rule_element__defines_description">Pomocí tohoto pravidla definujte proměnné pro opětovné použití běžných barev nebo velikostí ve vaší tabulce stylů.</string>
|
||||
<string name="snygg__rule_element__keyboard">Okno klávesnice</string>
|
||||
<string name="snygg__rule_element__key">Klávesa</string>
|
||||
<string name="snygg__rule_element__key_hint">Nápovědy klávesy</string>
|
||||
<string name="snygg__rule_element__key_popup">Vyskakovací okno klávesy</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Záhlaví schránky</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Položka schránky</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Vyskakovací nabídka položky schránky</string>
|
||||
<string name="snygg__rule_element__emoji_key">Klávesa emoji</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">Vyskakovací okno klávesy emoji</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Záložka emoji</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Rozložení vstupu na šířku</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Pole vstupu na šířku</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Akce vstupu na šířku</string>
|
||||
@@ -229,12 +220,9 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Navrhnuté slovo v chytré liště</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Navrhnutá položka v chytré liště</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">Odsazení navrhnutí v chytré liště</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Systémová navigační lišta</string>
|
||||
<string name="snygg__rule_selector__pressed">Stisknuto</string>
|
||||
<string name="snygg__rule_selector__focus">Zaměřeno</string>
|
||||
<string name="snygg__rule_selector__disabled">Zakázáno</string>
|
||||
<string name="snygg__property_name__width">Šířka</string>
|
||||
<string name="snygg__property_name__height">Výška</string>
|
||||
<string name="snygg__property_name__background">Pozadí</string>
|
||||
<string name="snygg__property_name__foreground">Popředí</string>
|
||||
<string name="snygg__property_name__border_color">Barva okraje</string>
|
||||
@@ -243,7 +231,6 @@
|
||||
<string name="snygg__property_name__font_family">Rodina písem</string>
|
||||
<string name="snygg__property_name__font_size">Velikost písma</string>
|
||||
<string name="snygg__property_name__font_style">Styl písma</string>
|
||||
<string name="snygg__property_name__font_variant">Varianta písma</string>
|
||||
<string name="snygg__property_name__font_weight">Tloušťka písma</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Výška stínu</string>
|
||||
<string name="snygg__property_name__shape">Tvar</string>
|
||||
@@ -262,10 +249,10 @@
|
||||
<string name="snygg__property_name__var_shape">Běžný tvar</string>
|
||||
<string name="snygg__property_name__var_shape_variant">Běžný tvar (varianta)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">Zdědit</string>
|
||||
<string name="snygg__property_value__defined_var">Odkaz na proměnnou</string>
|
||||
<string name="snygg__property_value__solid_color">Pevná barva</string>
|
||||
<string name="snygg__property_value__material_you_light_color">Barva Material You (světlá)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">Barva Material You (tmavá)</string>
|
||||
<string name="snygg__property_value__image_ref">Odkaz na obrázek</string>
|
||||
<string name="snygg__property_value__rectangle_shape">Obdélníkový tvar</string>
|
||||
<string name="snygg__property_value__circle_shape">Kruhový tvar</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">Tvar ořezaného rohu (dp)</string>
|
||||
@@ -275,7 +262,6 @@
|
||||
<string name="snygg__property_value__dp_size">Velikost (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">Velikost (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">Velikost (%)</string>
|
||||
<string name="snygg__property_value__defined_var">Odkaz na proměnnou</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Zvuky a vibrace</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Zvuková odezva / zvuky</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Povolit zvukovou odezvu</string>
|
||||
@@ -350,11 +336,8 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Poskytuje návrhy, zatímco píšete</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Režim zobrazování návrhů</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Blokovat možná urážlivá slova</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Návrhy obsahu schránky</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Navrhnout obsah dříve zkopírovaný do schránky</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Omezit návrhy ze schránky na</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">Položky zkopírované v posledních {v} s</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">Zobrazit návrhy na řádku poskytnuté službami automatického doplnění</string>
|
||||
<string name="pref__suggestion__incognito_mode__label" comment="Label of Incognito mode preference in Typing">Anonymní režim</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Oprava</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Automatická kapitalizace</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Kapitalizovat slova na základě aktuálního vstupního kontextu</string>
|
||||
@@ -428,18 +411,17 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Dlouhé stisknutí klávesy ke smazání</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Práh rychlosti přejetí</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Práh vzdálenosti přejetí</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Pokročilé</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Motiv nastavení</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Výchozí podle systému (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Světlý</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Tmavý</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Temná</string>
|
||||
<string name="pref__advanced__settings_accent_color__label" comment="Label of accent color preference in Advanced"> Nastavení barvy
|
||||
<string name="settings__other__title" comment="Title of Other settings">Ostatní</string>
|
||||
<string name="pref__other__settings_theme__label" comment="Label of Settings theme preference in Other">Motiv nastavení</string>
|
||||
<string name="pref__other__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Other">Podle systému (AMOLED)</string>
|
||||
<string name="pref__other__settings_theme__light" comment="Possible value of Settings theme preference in Other">Světlý</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">Tmavý</string>
|
||||
<string name="pref__other__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Other">AMOLED tmavý</string>
|
||||
<string name="pref__other__settings_accent_color__label" comment="Label of accent color preference in Other"> Barva nastavení
|
||||
</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Jazyk nastavení</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Zobrazit ikonu aplikace na domovské obrazovce</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Vždy povoleno na Android 10+ kvůli omezením systému</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">Anonymní režim</string>
|
||||
<string name="pref__other__settings_language__label" comment="Label of Settings language preference in Other">Jazyk nastavení</string>
|
||||
<string name="pref__other__show_app_icon__label" comment="Label of Show app icon preference in Other">Zobrazit ikonu aplikace na domovské obrazovce</string>
|
||||
<string name="pref__other__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Other for Android 10+">Vždy povoleno v systému Android 10+ kvůli systémovým omezením</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">O aplikaci</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Ikona aplikace FlorisBoard</string>
|
||||
@@ -561,6 +543,11 @@
|
||||
<string name="pref__clipboard__sync_from_system_clipboard__summary">Aktualizace systémové schránky také zahrnují schránku Floris</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__label">Synchronizovat do systémové schránky</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__summary">Aktualizace schránky Floris také zahrnují systémovou schránku</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">Návrhy schránky</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__label" comment="Preference title">Obsah návrhu schránky</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__summary" comment="Preference summary">Navrhnout obsah dříve zkopírovaný do schránky</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__summary` and is the first part">Omezit návrhy ze schránky na</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__label` and is the second part">Položky zkopírované v posledních {v} s</string>
|
||||
<string name="pref__clipboard__group_clipboard_history__label">Historie schránky</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__label">Zapnout historii schránky</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">Ponechat obsah schránky pro rychlý přístup</string>
|
||||
@@ -681,7 +668,6 @@
|
||||
<string name="ext__validation__error_stylesheet_path">Zadejte prosím platnou cestu tabulky stylů odpovídající {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Zadejte prosím název proměnné</string>
|
||||
<string name="ext__validation__error_property">Zadejte prosím platný název proměnné odpovídající {variable_name_regex}</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">Názvy proměnných ve FlorisCSS obvykle začínají dvěma spojovníky (--)</string>
|
||||
<string name="ext__validation__enter_color">Zadejte prosím řetězec barvy</string>
|
||||
<string name="ext__validation__error_color">Zadejte prosím platný řetězec barvy</string>
|
||||
<string name="ext__validation__enter_dp_size">Zadejte prosím velikost dp</string>
|
||||
@@ -757,8 +743,6 @@
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">Dynamická šířka a skrolovatelné</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_double_tap" comment="Enum value label">Zapnout Caps Lock při dvojitém klepnutí na Shift</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_cycle" comment="Enum value label">Přepnout na další krok kapitalizace při každém stisknutí klávesy Shift</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">Hexadecimální</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">Červená Zelená Modrá Alpha</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">Vždy zobrazit</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">Vždy zobrazit klávesnici po zavření jakéhokoli dialogu editoru</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">Nikdy nezobrazovat</string>
|
||||
@@ -827,7 +811,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Nikdy nezobrazovat</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Vždy zobrazovat</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Dynamicky zobrazovat</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Vypnuto</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Režim pro leváky</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Režim pro praváky</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Vlevo nahoře</string>
|
||||
|
||||
@@ -15,6 +15,24 @@
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Tekst-emoji</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Foretrukken emoji-hudfarve</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Foretrukken emoji-frisure</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">Emoji-historik</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">Aktiver emoji-historik</string>
|
||||
<string name="prefs__media__emoji_history_enabled__summary" comment="Preference summary">Bibehold nyligt brugte emojis til hurtig adgang</string>
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">Opdateringsstrategi (Fastgjorte)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">Opdateringsstrategi (Seneste)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">Maksimalt antal emner gemt</string>
|
||||
<string name="prefs__media__emoji_history_pinned_reset">Nulstil fastgjorte emojis</string>
|
||||
<string name="prefs__media__emoji_history_reset">Nulstil seneste emojis</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Emoji-anbefalinger</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Aktiver emoji-forslag</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Giv emoji-forslag imens du skriver</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Udløsertype</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Opdater emoji-historik</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Accepterede emoji-anbefalinger tilføjes til emoji-historikken</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Vis emoji-navn</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Emoji-forslag viser deres navn ved siden af emojien</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Minimal forespørgselslængde</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Maksimal antal muligheder</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smileys & Følelser</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Personer & Krop</string>
|
||||
@@ -25,6 +43,12 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objekter</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symboler</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Flag</string>
|
||||
<string name="emoji__history__empty_message" comment="Message if the emoji history is empty">Ingen nyligt brugte emojis fundet. Når du starter med at indtaste emojis, vil de dukke op her.</string>
|
||||
<string name="emoji__history__phone_locked_message" comment="Message to show if phone is locked">Åben din enhed for at tilgå din emoji-historik.</string>
|
||||
<string name="emoji__history__usage_tip" comment="Feature discoverability for actions of emoji history">Godt råd: Tryk og hold inde på en emojier i emoji-historikken for at fastgøre eller fjerne dem!</string>
|
||||
<string name="emoji__history__removal_success_message" comment="Toast message if user has used the delete action on an emoji in the emoji history">Fjernede {emoji} fra emoji historik</string>
|
||||
<string name="emoji__history__pinned">Fastgjorte</string>
|
||||
<string name="emoji__history__recent">Seneste</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Pil op</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Udfør pil op</string>
|
||||
@@ -36,21 +60,43 @@
|
||||
<string name="quick_action__arrow_right__tooltip">Udfør pil højre</string>
|
||||
<string name="quick_action__clipboard_clear_primary_clip__tooltip">Udfør ryd primær udklipsholder</string>
|
||||
<string name="quick_action__clipboard_copy" maxLength="12">Kopiér</string>
|
||||
<string name="quick_action__clipboard_copy__tooltip">Udfør udklipsholder kopiering</string>
|
||||
<string name="quick_action__clipboard_cut" maxLength="12">Klip</string>
|
||||
<string name="quick_action__clipboard_cut__tooltip">Udfør udklipsholder klip</string>
|
||||
<string name="quick_action__clipboard_paste" maxLength="12">Indsæt</string>
|
||||
<string name="quick_action__clipboard_paste__tooltip">Udfør udklipsholder indsæt</string>
|
||||
<string name="quick_action__clipboard_select_all" maxLength="12">Vælg alle</string>
|
||||
<string name="quick_action__clipboard_select_all__tooltip">Udfør udklipsholder marker alt</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard__tooltip">Åben udklipsholder historik</string>
|
||||
<string name="quick_action__ime_ui_mode_media" maxLength="12">Emoji</string>
|
||||
<string name="quick_action__ime_ui_mode_media__tooltip">Åbn emoji-panel</string>
|
||||
<string name="quick_action__settings__tooltip">Åbn indstillinger</string>
|
||||
<string name="quick_action__undo" maxLength="12">Fortryd</string>
|
||||
<string name="quick_action__undo__tooltip">Fortryd sidste indtastning</string>
|
||||
<string name="quick_action__redo" maxLength="12">Gentag</string>
|
||||
<string name="quick_action__redo__tooltip">Gentag sidste indtastning</string>
|
||||
<string name="quick_action__toggle_actions_overflow__tooltip">Vis eller skjul flere handlinger</string>
|
||||
<string name="quick_action__toggle_incognito_mode" maxLength="12">Inkognito</string>
|
||||
<string name="quick_action__toggle_incognito_mode__tooltip">Slå inkognito-tilstand til/fra</string>
|
||||
<string name="quick_action__toggle_autocorrect" maxLength="12">Stavekontrol</string>
|
||||
<string name="quick_action__toggle_autocorrect__tooltip">Slå stavekontrol til og fra</string>
|
||||
<string name="quick_action__voice_input" maxLength="12">Stemmeinput</string>
|
||||
<string name="quick_action__voice_input__tooltip" comment="IME stands for Input Method Editor and is indirectly equivalent to 'keyboard'.">Åbn stemmeinput-udbyder</string>
|
||||
<string name="quick_action__one_handed_mode" maxLength="12">Enhåndet</string>
|
||||
<string name="quick_action__one_handed_mode__tooltip">Skift enhåndstilstand</string>
|
||||
<string name="quick_action__drag_marker" maxLength="12" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Træk markør</string>
|
||||
<string name="quick_action__drag_marker__tooltip" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Nuværende træk-markør position</string>
|
||||
<string name="quick_action__noop" maxLength="12" comment="Noop=no operation; this action is only used as a placeholder in the actions editor drag and drop screen">Ingen</string>
|
||||
<string name="quick_action__noop__tooltip" comment="Noop=no operation; this action is only used as a placeholder in the actions editor drag and drop screen">Ingen handling</string>
|
||||
<string name="quick_actions_overflow__customize_actions_button">Tilpas handlinger</string>
|
||||
<string name="quick_actions_editor__header">Tilpas handlingsrækkefølge</string>
|
||||
<string name="quick_actions_editor__subheader_sticky_action">Klæbrig handling ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Dynamiske handlinger ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Skjulte handlinger ({n})</string>
|
||||
<string name="select_subtype_panel__header">Vælg undertype</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">Inkognitotilstand er nu aktiveret\n\n{app_name} lærer ikke ord fra dine indtastninger når denne tilstand er aktiv</string>
|
||||
<string name="incognito_mode__toast_after_disabled">Inkognitotilstand er nu deaktiveret som standard</string>
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">Indstillinger</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">Prøv din opsætning</string>
|
||||
@@ -68,18 +114,69 @@
|
||||
<string name="settings__localization__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">Ændre undertastatur</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Primært sprog</string>
|
||||
<string name="settings__localization__subtype_suggestion_provider" comment="Label for suggestion provider dropdown in subtype dialog">Inkognito-tilstand er nu aktiveret. Vil ikke lærer ord fra dine input mens denne tilstand er aktiv</string>
|
||||
<string name="settings__localization__subtype_numeric_layout" comment="Label for layout dropdown in subtype dialog">Numerisk opsætning</string>
|
||||
<string name="settings__localization__subtype_numeric_advanced_layout" comment="Label for layout dropdown in subtype dialog">Numerisk (avanceret) opsætning</string>
|
||||
<string name="settings__localization__subtype_select_locale" comment="Subtype select language title">Vælg sprog</string>
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">Vis alle</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">Det ser ud til, at der ikke er konfigureret nogle undertastaturer. I dette tilfælde faldes der tilbage på Engelsk/QWERTY!</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Dette undertastatur findes allerede!</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (ikke installeret)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Opsætninger</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Tema</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Tematilstand</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Solopgangstidspunkt</string>
|
||||
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Solnedgangstidspunkt</string>
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Dagstema</string>
|
||||
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Nattema</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Intern lagerplads</string>
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">Vælg dagstema</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Vælg nattema</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grupper</string>
|
||||
<string name="settings__theme_editor__rule_selectors"></string>
|
||||
<string name="snygg__rule_element__keyboard">Tastatur vindue</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Kode</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Optager…</string>
|
||||
<string name="settings__theme_editor__add_property">Tilføj egenskab</string>
|
||||
<string name="settings__theme_editor__edit_property">Rediger egenskab</string>
|
||||
<string name="settings__theme_editor__property_name">Egenskabsnavn</string>
|
||||
<string name="settings__theme_editor__property_value">Egenskabsværdi</string>
|
||||
<string name="snygg__rule_selector__pressed">Trykket</string>
|
||||
<string name="snygg__rule_selector__focus">Fokuseret</string>
|
||||
<string name="snygg__rule_selector__disabled">Deaktiveret</string>
|
||||
<string name="snygg__property_name__background">Baggrund</string>
|
||||
<string name="snygg__property_name__foreground">Forgrund</string>
|
||||
<string name="snygg__property_name__border_color">Kantfarve</string>
|
||||
<string name="snygg__property_name__border_style">Kantstil</string>
|
||||
<string name="snygg__property_name__border_width">Kantbredde</string>
|
||||
<string name="snygg__property_name__font_family">Skrifttype</string>
|
||||
<string name="snygg__property_name__font_size">Skriftstørrelse</string>
|
||||
<string name="snygg__property_name__font_style">Skriftstil</string>
|
||||
<string name="snygg__property_name__font_weight">Skrifttykkelse</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Skyggehøjde</string>
|
||||
<string name="snygg__property_name__shape">Form</string>
|
||||
<string name="snygg__property_name__var_primary">Primær farve</string>
|
||||
<string name="snygg__property_name__var_primary_variant">Primær farve (variant)</string>
|
||||
<string name="snygg__property_name__var_secondary">Sekundær farve</string>
|
||||
<string name="snygg__property_name__var_secondary_variant">Sekundær farve (variant)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">Overtag</string>
|
||||
<string name="snygg__property_value__solid_color">Ensfarvet</string>
|
||||
<string name="snygg__property_value__material_you_light_color">Material You color (Light)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">Material You color (Dark)</string>
|
||||
<string name="snygg__property_value__rectangle_shape">Rektangelform</string>
|
||||
<string name="snygg__property_value__circle_shape">Cirkelform</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Aktivér lydfeedback</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__label" comment="Preference title">Aktiver haptisk feedback</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_mode__label" comment="Preference title">Vibrationstilstand</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">Vibrationsvarighed</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">Vibrationsstyrke</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_press__label" comment="Preference title">Tasttryksvibration</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_long_press__label" comment="Preference title">Langt tasttryksvibration</string>
|
||||
<string name="pref__input_feedback__any_feat_gesture_swipe__summary" comment="Preference summary">ikke implementeret</string>
|
||||
<string name="settings__keyboard__title" comment="Title of Keyboard preferences screen">Tastatur</string>
|
||||
<string name="pref__keyboard__number_row__label" comment="Preference title">Nummerække</string>
|
||||
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Opsætning</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Enhåndstilstand</string>
|
||||
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Enhåndstilstand tastaturbredde</string>
|
||||
<string name="pref__keyboard__height_factor__label" comment="Preference title">Tastaturhøjde</string>
|
||||
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Tastetryk</string>
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">Popup synlighed</string>
|
||||
<string name="pref__keyboard__popup_enabled__summary" comment="Preference summary">Hvis popup ved tastetryk</string>
|
||||
@@ -88,9 +185,12 @@
|
||||
<string name="settings__smartbar__title" comment="Title of Smartbar screen">SmartBjælke</string>
|
||||
<string name="pref__smartbar__enabled__label" comment="Preference title">Aktivér Smartbar</string>
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Vil blive vist over tastaturet</string>
|
||||
<string name="pref__smartbar__layout__label" comment="Preference title">Opsætning</string>
|
||||
<!-- Typing strings -->
|
||||
<string name="settings__typing__title" comment="Title of Typing screen">Indtastning</string>
|
||||
<string name="pref__suggestion__title" comment="Preference group title">Forslag</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Udklipsholder indholdsforslag</string>
|
||||
<string name="pref__suggestion__enabled__label" comment="Preference title">Vis anbefalinger</string>
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Vis forslag imens du skriver</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Rettelser</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Automatisk stort bogstav</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Gør bogstaver i ord store baseret på nuværende inputskontekst</string>
|
||||
@@ -98,9 +198,15 @@
|
||||
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Caps lock vil forblive aktiveret ved skift af tekstfelter</string>
|
||||
<string name="pref__correction__double_space_period__label" comment="Preference title">Dobbelt-mellemrumspunktum</string>
|
||||
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Tast to gange på mellemrum for at indætte et punktum efterfulgt af mellemrum</string>
|
||||
<string name="pref__spelling__title" comment="Preference group title">Stavning</string>
|
||||
<string name="pref__spelling__language_mode__label" comment="Label of Language mode pref">Sprog</string>
|
||||
<string name="settings__dictionary__title" comment="Title of the User dictionaries screen">Brugerordbøger</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">Aktiver systembrugerordbøger</string>
|
||||
<string name="settings__udm__all_languages" comment="Label of the For all languages entry in the language list">For alle sprog</string>
|
||||
<string name="settings__udm__dialog__title_add" comment="Label for the title (when in adding mode) in the user dictionary add/edit dialog">Tilføj ord</string>
|
||||
<string name="settings__udm__dialog__title_edit" comment="Label for the title (when in editing mode) in the user dictionary add/edit dialog">Rediger ord</string>
|
||||
<string name="settings__udm__dialog__word_label" comment="Label for the word in the user dictionary add/edit dialog">Ord</string>
|
||||
<string name="settings__udm__dialog__word_error_empty" comment="Error label for the word in the user dictionary add/edit dialog">Indtast venligst et ord</string>
|
||||
<string name="settings__udm__dialog__shortcut_label" comment="Label for the shortcut in the user dictionary add/edit dialog">Genvej (valgfri)</string>
|
||||
<string name="settings__gestures__title" comment="Title of Gestures screen">Bevægelser & Strygeskrivning</string>
|
||||
<string name="pref__glide__title" comment="Preference group title">Strygeskrivning</string>
|
||||
@@ -111,22 +217,38 @@
|
||||
<string name="pref__gestures__swipe_left__label" comment="Preference title">Stryg til venstre</string>
|
||||
<string name="pref__gestures__swipe_right__label" comment="Preference title">Swipe til højre</string>
|
||||
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Space bar knalde op</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Avanceret</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Lys</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Mørk</string>
|
||||
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Stryg til venstre på mellemrumstasten</string>
|
||||
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Stryg til højre på mellemrumstasten</string>
|
||||
<string name="pref__gestures__space_bar_long_press__label" comment="Preference title">Langt tryk på mellemrumstasten</string>
|
||||
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Stryg til venstre på slettetasten</string>
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Langt tryk på slettetasten</string>
|
||||
<string name="settings__other__title" comment="Title of Other settings">Andet</string>
|
||||
<string name="pref__other__settings_theme__label" comment="Label of Settings theme preference in Other">Temaindstillinger</string>
|
||||
<string name="pref__other__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Other">System standard (AMOLED)</string>
|
||||
<string name="pref__other__settings_theme__light" comment="Possible value of Settings theme preference in Other">Lys</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">Mørk</string>
|
||||
<string name="pref__other__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Other">AMOLED mørk</string>
|
||||
<string name="pref__other__settings_language__label" comment="Label of Settings language preference in Other">Sprogindstillinger</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Omkring</string>
|
||||
<string name="about__view_licenses" comment="Label of View licenses button in About">Open source licenser</string>
|
||||
<string name="about__view_privacy_policy" comment="Label of View privacy policy button in About">Privatlivspolitik</string>
|
||||
<string name="about__view_source_code" comment="Label of View source code button in About">Source kode</string>
|
||||
<string name="about__license__title" comment="Title of Open-source licenses dialog">Open source licenser</string>
|
||||
<string name="about__version__title" comment="Preference title">Version</string>
|
||||
<string name="about__version_copied__title" comment="Title of the toast for copying the version string">Version kopieret til udklipsholderen</string>
|
||||
<string name="about__version_copied__error" comment="Title of the error toast for copying the version string">Noget gik galt: {error_message}</string>
|
||||
<string name="about__changelog__title" comment="Preference title">Ændringslog</string>
|
||||
<string name="about__changelog__summary" comment="Preference summary">Nyheder</string>
|
||||
<string name="about__repository__title" comment="Preference title">Projektarkiv (GitHub)</string>
|
||||
<string name="about__repository__summary" comment="Preference summary">Kildekode, diskussioner, problemer og information</string>
|
||||
<string name="about__privacy_policy__title" comment="Preference title">Privatlivspolitik</string>
|
||||
<string name="about__privacy_policy__summary" comment="Preference summary">Privatlivspolitikken for dette projekt</string>
|
||||
<string name="about__project_license__title" comment="Preference title">Projektlicens</string>
|
||||
<!-- Setup UI strings -->
|
||||
<string name="setup__title" comment="Title of Setup">Velkommen!</string>
|
||||
<string name="setup__footer__privacy_policy" comment="Privacy policy label for URL">Privatlivspolitik</string>
|
||||
<string name="setup__footer__repository" comment="Repository label for URL">Projektarkiv</string>
|
||||
<string name="setup__enable_ime__title">Aktivér {app_name}</string>
|
||||
<string name="setup__select_ime__title">Vælg {app_name}</string>
|
||||
<string name="setup__select_ime__switch_keyboard_btn">Skift tastatur</string>
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<string name="quick_actions_editor__subheader_sticky_action">Fixierte Aktion ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Dynamische Aktionen ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Versteckte Aktionen ({n})</string>
|
||||
<string name="select_subtype_panel__header"></string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">Inkognito-Modus ist nun aktiviert \n\n{app_name} wird während dieses Modus keine neuen Wörter lernen</string>
|
||||
<string name="incognito_mode__toast_after_disabled">Inkognito-Modus ist nun standardmäßig deaktiviert</string>
|
||||
@@ -151,8 +152,6 @@
|
||||
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Sonnenuntergangszeit</string>
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Helles Design</string>
|
||||
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Dunkles Design</string>
|
||||
<string name="pref__theme__theme_accent_color__label" comment="Label of accent color preference in Theme"> Akzentfarbe (Material you designs)
|
||||
</string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Installierte Designs verwalten</string>
|
||||
<string name="pref__theme__source_assets" comment="Label for the theme source field">FlorisBoard App Ressourcen</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Interner Speicher</string>
|
||||
@@ -161,13 +160,11 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Nacht-Design auswählen</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">Editoreinstellungen</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">Bearbeitungsmodus</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Zeige Farben als</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Zeige Tastatur nach Dialogen</string>
|
||||
<string name="settings__theme_editor__add_rule">Regel hinzufügen</string>
|
||||
<string name="settings__theme_editor__edit_rule">Regel bearbeiten</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Für das Stylesheet sind keine Regeln definiert. Füge eine Regel hinzu, um dieses Stylesheet anzupassen.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Diese Stylesheetregel ist schon definiert.</string>
|
||||
<string name="settings__theme_editor__rule_element">Zielelement</string>
|
||||
<string name="settings__theme_editor__rule_codes">Ziel-Codes</string>
|
||||
<string name="settings__theme_editor__rule_groups">Gruppen</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Umschalt-Status</string>
|
||||
@@ -195,18 +192,11 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">Ist Nachtthema</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">Ist randlos</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">Stylesheetpfad</string>
|
||||
<string name="snygg__rule_element__defines">Variablen</string>
|
||||
<string name="snygg__rule_element__defines_description">Definiere Variablen innerhalb dieser Regel, um gängige Farben oder Größen in deinem Stylesheet wiederzuverwenden.</string>
|
||||
<string name="snygg__rule_element__keyboard">Tastaturfenster</string>
|
||||
<string name="snygg__rule_element__key">Taste</string>
|
||||
<string name="snygg__rule_element__key_hint">Tastenhinweis</string>
|
||||
<string name="snygg__rule_element__key_popup">Tasten Pop-Up</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Zwischenablagekopfzeile</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Zwischenablagenitem</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Zwischensblagenitem-Popup</string>
|
||||
<string name="snygg__rule_element__emoji_key">Emoji Taste</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">Emoji Tasten Pop-Up</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Emoji Tab</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Eingabeanordnung im Querformat</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Eingabefeld im Querformat</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Eingabeaktion im Querformat</string>
|
||||
@@ -229,12 +219,9 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Smartbar Wortkandidat</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Smartbar Kandidatenclip</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">Smartbar Kandidaten-Abstandshalter</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">System-Navigationsleiste</string>
|
||||
<string name="snygg__rule_selector__pressed">Gedrückt</string>
|
||||
<string name="snygg__rule_selector__focus">Fokussiert</string>
|
||||
<string name="snygg__rule_selector__disabled">Deaktiviert</string>
|
||||
<string name="snygg__property_name__width">Breite</string>
|
||||
<string name="snygg__property_name__height">Höhe</string>
|
||||
<string name="snygg__property_name__background">Hintergrund</string>
|
||||
<string name="snygg__property_name__foreground">Vordergrund</string>
|
||||
<string name="snygg__property_name__border_color">Rahmenfarbe</string>
|
||||
@@ -243,7 +230,6 @@
|
||||
<string name="snygg__property_name__font_family">Schriftart</string>
|
||||
<string name="snygg__property_name__font_size">Schriftgröße</string>
|
||||
<string name="snygg__property_name__font_style">Schriftstil</string>
|
||||
<string name="snygg__property_name__font_variant">Schriftvariante</string>
|
||||
<string name="snygg__property_name__font_weight">Schriftstärke</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Höhe des Schattens</string>
|
||||
<string name="snygg__property_name__shape">Form</string>
|
||||
@@ -262,10 +248,10 @@
|
||||
<string name="snygg__property_name__var_shape">Gemeinsame Form</string>
|
||||
<string name="snygg__property_name__var_shape_variant">Gemeinsame Form (Variante)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">Erben</string>
|
||||
<string name="snygg__property_value__defined_var">Variable referenzieren</string>
|
||||
<string name="snygg__property_value__solid_color">Einfarbig</string>
|
||||
<string name="snygg__property_value__material_you_light_color">Material You Farbe (Hell)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">Material You Farbe (Dunkel)</string>
|
||||
<string name="snygg__property_value__image_ref">Bildreferenz</string>
|
||||
<string name="snygg__property_value__rectangle_shape">Rechteckform</string>
|
||||
<string name="snygg__property_value__circle_shape">Kreisform</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">Form mit eckigen Ecken (dp)</string>
|
||||
@@ -275,7 +261,6 @@
|
||||
<string name="snygg__property_value__dp_size">Größe (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">Größe (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">Größe (%)</string>
|
||||
<string name="snygg__property_value__defined_var">Variable referenzieren</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Ton & Vibration</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Ton Rückmeldung / Klänge</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Ton Rückmeldung aktivieren</string>
|
||||
@@ -350,10 +335,6 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Bietet Vorschläge an während Sie tippen</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Darstellungsart für Vorschläge</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Möglicherweise unangebrachte Wörter blockieren</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Inhalt der Zwischenablage</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Zuvor kopierte Inhalte vorschlagen</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Beschränkung für die Vorschläge der Zwischenablage</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">Elemente, kopiert in den letzten {v} s</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">Zeige Inline-Vorschläge von Autofill-Diensten</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Korrekturen</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Autom. Groß-/Kleinschreibung</string>
|
||||
@@ -428,18 +409,7 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Aktion bei lang gedrückter Löschtaste</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Gesten-Geschwindigkeitsschwelle</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Gesten-Distanzschwelle</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Erweitert</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">App-Design</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Systemstandard (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Hell</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Dunkel</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Dunkel</string>
|
||||
<string name="pref__advanced__settings_accent_color__label" comment="Label of accent color preference in Advanced"> Akzentfarben-Einstellungen
|
||||
</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">App-Sprache</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Zeige die App in der Übersicht</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Immer aktiviert in Android 10+ aufgrund von System-Beschränkungen</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">Inkognito-Modus</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">Dunkel</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Über</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">App-Icon von FlorisBoard</string>
|
||||
@@ -558,6 +528,7 @@
|
||||
<string name="pref__clipboard__sync_from_system_clipboard__summary">Änderungen in der Systemzwischenablage aktualisieren auch die interne Zwischenablage</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__label">Zur Systemzwischenablage synchronisieren</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__summary">Aktualisierungen der Floris Zwischenablage aktualisieren auch die Systemzwischenablage</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">Vorschläge aus der Zwischenablage</string>
|
||||
<string name="pref__clipboard__group_clipboard_history__label">Zwischenablageverlauf</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__label">Verlauf für Zwischenablage aktivieren</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">Speichere Elemente der Zwischenablage für schnellen Zugriff</string>
|
||||
@@ -677,7 +648,6 @@
|
||||
<string name="ext__validation__error_stylesheet_path">Bitte einen Stylesheet-Pfad eingeben, welcher zu {stylesheet_path_regex} passt</string>
|
||||
<string name="ext__validation__enter_property">Bitte gib einen Variablennamen an</string>
|
||||
<string name="ext__validation__error_property">Bitte einen gültigen Variablennamen eingeben, welcher zu {variable_name_regex} passt</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">Nach FlorisCSS-Konvention beginnt ein Variablenname mit zwei Bindestrichen (--)</string>
|
||||
<string name="ext__validation__enter_color">Bitte gib einen Farbstring ein</string>
|
||||
<string name="ext__validation__error_color">Bitte gib einen gültigen Farbstring ein</string>
|
||||
<string name="ext__validation__enter_dp_size">Bitte gib eine dp-Größe an</string>
|
||||
@@ -753,8 +723,6 @@
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">Dynamische Breite & scrollbar</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_double_tap" comment="Enum value label">Aktiviere die Feststelltaste durch Doppeltippen von Shift</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_cycle" comment="Enum value label">Wechsel mit jedem Drücken der Shift-Taste zur nächsten Großschreibstufe</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">Hexadezimal</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">Rot Grün Blau Alpha</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">Immer anzeigen</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">Immer die Tastatur nach Schließen eines Editordialogs anzeigen</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">Nie anzeigen</string>
|
||||
@@ -823,7 +791,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Nie anzeigen</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Immer anzeigen</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Dynamisch anzeigen</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Aus</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Linkshänder-Modus</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Rechtshänder-Modus</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Anfang oben</string>
|
||||
|
||||
@@ -138,7 +138,6 @@
|
||||
<!-- Typing strings -->
|
||||
<string name="pref__suggestion__title" comment="Preference group title">Προτάσεις</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Λειτουργία προβολής προτάσεων</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Προτάσεις περιεχομένου προχείρου</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Διορθώσεις</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Αυτόματη χρήση κεφαλαίων</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Κεφαλαιοποίηση λέξεων βάσει του παρόντος περιεχομένου εισαγωγής</string>
|
||||
@@ -192,14 +191,6 @@
|
||||
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Σάρωση αριστερά στο πλήκτρο διαγραφής</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Όριο ταχύτητας σάρωσης</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Όριο απόστασης σάρωσης</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Προηγμένες επιλογές</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Θέμα ρυθμίσεων</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Φωτεινό</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Σκούρο</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Σκούρο</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Γλώσσα ρυθμίσεων</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Εμφάνιση του εικονιδίου της εφαρμογής στον εκκινητή</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Πάντα ενεργοποιημένο σε Android 10+ λόγω περιορισμών του συστήματος</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Σχετικά με</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Εικονίδιο εφαρμογής του FlorisBoard</string>
|
||||
@@ -393,7 +384,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Να μην εμφανίζεται ποτέ</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Να εμφανίζεται πάντα</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Να εμφανίζεται δυναμικά</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Ανενεργό</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Λειτουργία για αριστερόχειρες</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Λειτουργία για δεξιόχειρες</string>
|
||||
<string name="enum__spelling_language_mode__use_system_languages" comment="Enum value label">Χρήση γλωσσών συστήματος</string>
|
||||
|
||||
@@ -21,20 +21,22 @@
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">Ĝisdatigon strategio (Alpinglitaj)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">Ĝisdatigon strategio (Ĵusaj)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">Maksimumo da konservendaj eroj</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Emoĝija sugestoj</string>
|
||||
<string name="prefs__media__emoji_history_pinned_reset">Forgesi alpinglitajn emoĝiojn</string>
|
||||
<string name="prefs__media__emoji_history_reset">Forgesi ĵusajn emoĝiojn</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Emoĝiaj sugestoj</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Aktivigi emoĝiajn sugestojn</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Havigi emoĝiajn sugestojn dum ke vi tajpi</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Havigi emoĝiajn sugestojn dum ke vi tajpas</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Ekigon tipo</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Ĝisdatigi emoĝian historion</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Akcepti sugestitajn emoĝiojn aldonas ilin al la emoĝia historio</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Montri la nomojn de la emoĝioj</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Emoĝiaj sugestoj vidigi ĝiajn nomojn apude de la emoĝioj</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Minimuma mendon longo</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Minimuma longo de la mendo</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Maksimuma nombro da sugestoj</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Mienetoj & Emocioj</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Homoj & Korpo</string>
|
||||
<string name="emoji__category__animals_nature" comment="Emoji category name">Bestoj & Misvojo</string>
|
||||
<string name="emoji__category__animals_nature" comment="Emoji category name">Bestoj & Naturo</string>
|
||||
<string name="emoji__category__food_drink" comment="Emoji category name">Manĝaĵo & Trinkaĵo</string>
|
||||
<string name="emoji__category__travel_places" comment="Emoji category name">Vojaĝo & Lokoj</string>
|
||||
<string name="emoji__category__activities" comment="Emoji category name">Aktivaĵoj</string>
|
||||
@@ -95,6 +97,7 @@
|
||||
<string name="quick_actions_editor__subheader_sticky_action">Fiksita ago ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Dinamikaj agoj ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Kaŝitaj agoj ({n})</string>
|
||||
<string name="select_subtype_panel__header">Elekti subspecon</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">Inkognita moduso estas nun aktiva \n\n{app_name} ne lernos vortojn el via enigo dum ke tiu moduso estas aktiva</string>
|
||||
<string name="incognito_mode__toast_after_disabled">Inkognita moduso estas nun implicite malaktiva</string>
|
||||
@@ -121,7 +124,7 @@
|
||||
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">Simbolojn ĉefa aranĝo</string>
|
||||
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">Simbolojn flanka aranĝo</string>
|
||||
<string name="settings__localization__subtype_composer" comment="Label for composer dropdown in subtype dialog.">Kompostilo</string>
|
||||
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">Ĉefa monosigno</string>
|
||||
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">Ĉefa mona signo</string>
|
||||
<string name="settings__localization__subtype_numeric_layout" comment="Label for layout dropdown in subtype dialog">Nombra aranĝo</string>
|
||||
<string name="settings__localization__subtype_numeric_advanced_layout" comment="Label for layout dropdown in subtype dialog">Nombra (kroma) aranĝo</string>
|
||||
<string name="settings__localization__subtype_numeric_row_layout" comment="Label for layout dropdown in subtype dialog">Nombran vicon aranĝo</string>
|
||||
@@ -136,7 +139,7 @@
|
||||
<string name="settings__localization__suggested_subtype_presets_none_found" comment="Suggested presets none found">Neniu subspeco jam agordita disponebla. Uzu suban butonon por vidi ĉiujn jam agorditajn subspecojn.</string>
|
||||
<string name="settings__localization__subtype_presets" comment="Subtype presets dialog title">Subspecoj jam agorditaj</string>
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">Montri ĉiujn</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Ĉi tiu subtipo jam ekzistas!</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Ĉi tiu subspeco jam ekzistas!</string>
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Almenaŭ unu kampo ne havas valoron elektitan. Bonvolu elekti valoro(j)n por tiu(j) kampo(j).</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (ne instalita)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Aranĝoj</string>
|
||||
@@ -149,32 +152,85 @@
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Taga etoso</string>
|
||||
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Nokta etoso</string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Administri instalitajn etosojn</string>
|
||||
<string name="pref__theme__source_assets" comment="Label for the theme source field">Rimedoj apon FlorisBoard</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Interna memoro</string>
|
||||
<string name="pref__theme__source_external" comment="Label for the theme source field">Ekstera provizanto</string>
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">Elekti tagan etoson</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Elekti noktan etoson</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Montri kolorojn kiel</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">Redakta nivelo</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Montri klavaron post dialogoj</string>
|
||||
<string name="settings__theme_editor__add_rule">Aldoni regulon</string>
|
||||
<string name="settings__theme_editor__edit_rule">Redakti la regulon</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Tiu stilfolio havas neniun regulon difinitan. Aldonu regulon por komenci agordi tiu stilfolio.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Tiu stilfolia regulo estas jam difinita.</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grupoj</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Usklaj statoj</string>
|
||||
<string name="settings__theme_editor__add_code">Aldoni klavaran kodon</string>
|
||||
<string name="settings__theme_editor__edit_code">Redakti klavaran kodon</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Tiu klavaran kodon estas jam difinita.</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Kodo</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Registrante…</string>
|
||||
<string name="settings__theme_editor__add_property">Aldoni propraĵon</string>
|
||||
<string name="settings__theme_editor__edit_property">Redakti propraĵon</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Propraĵo kun tiu ĉi nomo jam ekzistas en la nuna regulo.</string>
|
||||
<string name="settings__theme_editor__property_name">Propraĵa nomo</string>
|
||||
<string name="settings__theme_editor__property_value">Propraĵa valoro</string>
|
||||
<string name="settings__theme_editor__property_value_shape_apply_for_all_corners">Apliki al ĉiuj anguloj</string>
|
||||
<string name="settings__theme_editor__property_value_color_dialog_title">Redakti koloran ĉenon</string>
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">Estas nokta etoso</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Tondujon ĉapo</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Tondujon ero</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Tonduja eron ŝpruco</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">Estas sen bordero</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">Stilfolia vojo</string>
|
||||
<string name="snygg__rule_element__key">Klavo</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Tonduja ĉapo</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Tonduja ero</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Tondujan eron ŝpruco</string>
|
||||
<string name="snygg__rule_element__glide_trail">Ŝova spuro</string>
|
||||
<string name="snygg__rule_element__one_handed_panel">Unu-mana panelo</string>
|
||||
<string name="snygg__rule_element__smartbar">LertaStrio</string>
|
||||
<string name="snygg__property_name__background">Fono</string>
|
||||
<string name="snygg__property_name__foreground">Malfono</string>
|
||||
<string name="snygg__property_name__border_color">Bordera koloro</string>
|
||||
<string name="snygg__property_name__border_style">Bordera stilo</string>
|
||||
<string name="snygg__property_name__border_width">Bordera larĝo</string>
|
||||
<string name="snygg__property_name__font_family">Tipara familio</string>
|
||||
<string name="snygg__property_name__font_size">Tipara grando</string>
|
||||
<string name="snygg__property_name__font_style">Tipara stilo</string>
|
||||
<string name="snygg__property_name__shape">Formo</string>
|
||||
<string name="snygg__property_name__var_primary">Ĉefa koloro</string>
|
||||
<string name="snygg__property_name__var_primary_variant">Ĉefa koloro (varianto)</string>
|
||||
<string name="snygg__property_name__var_secondary">Malĉefa koloro</string>
|
||||
<string name="snygg__property_name__var_secondary_variant">Malĉefa koloro (varianto)</string>
|
||||
<string name="snygg__property_value__material_you_light_color">Material You koloro (Hela)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">Material You koloro (Malhela)</string>
|
||||
<string name="snygg__property_value__rectangle_shape">Ortangula formo</string>
|
||||
<string name="snygg__property_value__circle_shape">Cirkla formo</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">Tondita angula formo (dp)</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_percent">Tondita angula formo (%)</string>
|
||||
<string name="snygg__property_value__rounded_corner_shape_dp">Rondigita angula formo (dp)</string>
|
||||
<string name="snygg__property_value__rounded_corner_shape_percent">Rondigita angula formo (%)</string>
|
||||
<string name="snygg__property_value__dp_size">Grando (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">Grando (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">Grando (%)</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Sonoj & Vibradoj</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Sona retrokuplo / Sonoj</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Ŝalti sonan retrokuplon</string>
|
||||
<string name="pref__input_feedback__audio_enabled__summary_disabled" comment="Preference summary">Neniam soni je enigoj, senrigarde al sistemaj agordoj</string>
|
||||
<string name="pref__input_feedback__audio_volume__label" comment="Preference title">Sona laŭteco je enigoj</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_press__label" comment="Preference title">Sonoj je tuŝoj klavojn</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_long_press__label" comment="Preference title">Sonoj je longaj tuŝoj klavojn</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_repeated_action__label" comment="Preference title">Sonoj je ripetitaj klavaj agoj</string>
|
||||
<string name="pref__input_feedback__group_haptic__label" comment="Preference group title">Tuŝa retrokuplo / Vibrado</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__label" comment="Preference title">Ŝalti tuŝan retrokuplon</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__summary_disabled" comment="Preference summary">Neniam vibri je enigoj, senrigarde al sistemaj agordoj</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_mode__label" comment="Preference title">Vibradon reĝimo</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">Vibradon daŭro</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">Vibradon intenseco</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__summary_no_vibrator" comment="Preference summary">Tiu funkcio bezonas aparatan vibrilon, kiu ŝajnas malesti en tiu aparato</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__summary_no_amplitude_ctrl" comment="Preference summary">Tiu funkcio necesas subtenon de la kontrolo aparataran amplitudon, kiu mankas en via aparato</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__summary_unsupported_android_version" comment="Preference summary">Tiu funkcio necesas subtenon de la kontrolo amplitudon, kiu estas nur disponebla en Android 8.0 aŭ pli nova</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_press__label" comment="Preference title">Vibrado je tuŝoj klavojn</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_long_press__label" comment="Preference title">Vibrado je longaj tuŝoj klavojn</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_repeated_action__label" comment="Preference title">Vibrado je ripetitaj klavaj agoj</string>
|
||||
<string name="pref__input_feedback__any_feat_key_press__summary" comment="Preference summary">ekz. klavojn, butonojn, emoĝiajn langetojn</string>
|
||||
<string name="pref__input_feedback__any_feat_key_long_press__summary" comment="Preference summary">ekz. ŝprucmenuo</string>
|
||||
<string name="pref__input_feedback__any_feat_key_repeated_action__summary" comment="Preference summary">ekz. forigklavon</string>
|
||||
@@ -194,8 +250,8 @@
|
||||
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Unu-mana moduso</string>
|
||||
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Unu-manan modusan klavaron larĝo</string>
|
||||
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Pejzaĝa plenekrana enigo</string>
|
||||
<string name="pref__keyboard__height_factor__label" comment="Preference title">Klavaron alteco</string>
|
||||
<string name="pref__keyboard__key_spacing__label" comment="Preference title">Klavojn interspaco</string>
|
||||
<string name="pref__keyboard__height_factor__label" comment="Preference title">Alteco klavaron</string>
|
||||
<string name="pref__keyboard__key_spacing__label" comment="Preference title">Interspaco inter la klavoj</string>
|
||||
<string name="pref__keyboard__bottom_offset__label" comment="Preference title">Suba senenhava spaco</string>
|
||||
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Klavojn tuŝo</string>
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">Ŝprucojn videblo</string>
|
||||
@@ -217,15 +273,14 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Havigi sugestojn dum ke vi tajpi</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Reĝimo de vidigo de la sugestoj</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Bloki eble ofendajn vortojn</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Tondujan enhavon sugestoj</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Sugesti antaŭe kopiitan tondujan enhavon</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Limigi tondujajn sugestojn je</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">Eroj kopiitaj dum la lastaj {v} s</string>
|
||||
<string name="pref__suggestion__incognito_mode__label" comment="Label of Incognito mode preference in Typing">Inkognita moduso</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Korektadoj</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Aŭto-majuskligo</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Majuskligi vortojn laŭ la ĉirkaŭteksto de la nuna enigo</string>
|
||||
<string name="pref__correction__auto_space_punctuation__label" comment="Preference title">Aŭto-spaceti post interpunkcio</string>
|
||||
<string name="pref__correction__auto_space_punctuation__summary" comment="Preference summary">Aŭtomate enigi spaceton post interpunkcio</string>
|
||||
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">Memori Fiks. Maj. staton</string>
|
||||
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Fiksa majuskligo restos aktiva kiam movinte al alia teksta kampo</string>
|
||||
<string name="pref__correction__double_space_period__label" comment="Preference title">Duoblan spaceton punkto</string>
|
||||
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Dufoje tuŝi la spacetklavo enigas punkton kaj spaceto sekve</string>
|
||||
<string name="pref__spelling__title" comment="Preference group title">Literumado</string>
|
||||
@@ -233,15 +288,15 @@
|
||||
<string name="pref__spelling__language_mode__label" comment="Label of Language mode pref">Lingvoj</string>
|
||||
<string name="pref__spelling__use_contacts__label" comment="Label of Use contact list pref">Uzi nomojn el kontaktoj</string>
|
||||
<string name="pref__spelling__use_udm_entries__label" comment="Label of Use user dictionary entries pref">Uzi enigaĵojn de la uzula vortaro</string>
|
||||
<string name="settings__dictionary__title" comment="Title of the User dictionaries screen">Uzanton vortaroj</string>
|
||||
<string name="settings__dictionary__title" comment="Title of the User dictionaries screen">Vortaroj uzanton</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">Ŝalti sisteman uzulan vortaron</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">Sugesti vortojn konservitajn en la sistema uzula vortaro</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__label" comment="Preference title">Mastrumi sisteman uzulan vortaron</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">Aldoni, vidi kaj forigi enigaĵoj el la sistema uzula vortaro</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">Aldoni, vidi kaj forigi enigaĵojn el la sistema uzula vortaro</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__label" comment="Preference title">Ŝalti internan uzulan vortaron</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__summary" comment="Preference summary">Sugesti vortojn konservitajn en la interna uzula vortaro</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__label" comment="Preference title">Mastrumi internan uzulan vortaron</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__summary" comment="Preference summary">Aldoni, vidi kaj forigi enigaĵoj el la interna uzula vortaro</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__summary" comment="Preference summary">Aldoni, vidi kaj forigi enigaĵojn el la interna uzula vortaro</string>
|
||||
<string name="settings__udm__title_floris" comment="Title of the User Dictionary Manager activity for internal">Interna uzula vortaro</string>
|
||||
<string name="settings__udm__title_system" comment="Title of the User Dictionary Manager activity for system">Sistema uzula vortaro</string>
|
||||
<string name="settings__udm__no_words_in_dictionary" comment="String to show if no words are present in the dictionary">Tiu uzula vortaro enhavas neniun vorton.</string>
|
||||
@@ -268,6 +323,7 @@
|
||||
<string name="pref__glide__show_trail__label" comment="Preference title">Montri ŝovan spuron</string>
|
||||
<string name="pref__glide__show_trail__summary" comment="Preference summary">Malaperonta post ĉiu vorto</string>
|
||||
<string name="pref__glide_trail_fade_duration">Daŭro fadon de la ŝova spuro</string>
|
||||
<string name="pref__glide__show_preview">Montri antaŭvidon dum ŝovtajpado</string>
|
||||
<string name="pref__glide__immediate_backspace_deletes_word__label">Ĉiam forigi vorton</string>
|
||||
<string name="pref__glide__immediate_backspace_deletes_word__summary">Tuŝi la forigklavon tuj ŝovo forigas la tutan vorton</string>
|
||||
<string name="pref__gestures__general_title" comment="Preference group title">Ĝeneralaj gestoj</string>
|
||||
@@ -285,15 +341,17 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Longa forigklavon tuŝo</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Ŝovumadon rapidosojlo</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Ŝovumadon distancosojlo</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Kromaj agordoj</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Agordojn etoso</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Sistema defaŭlta (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Hela</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Malhela</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED malhela</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Agordojn lingvo</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Montri aplikaĵo bildeto en aplikaĵolanĉilo</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">Inkognita moduso</string>
|
||||
<string name="settings__other__title" comment="Title of Other settings">Aliaj</string>
|
||||
<string name="pref__other__settings_theme__label" comment="Label of Settings theme preference in Other">Agordojn etoso</string>
|
||||
<string name="pref__other__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Other">Sistema defaŭlta (AMOLED)</string>
|
||||
<string name="pref__other__settings_theme__light" comment="Possible value of Settings theme preference in Other">Hela</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">Malhela</string>
|
||||
<string name="pref__other__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Other">AMOLED malhela</string>
|
||||
<string name="pref__other__settings_accent_color__label" comment="Label of accent color preference in Other"> Agordojn baza koloro
|
||||
</string>
|
||||
<string name="pref__other__settings_language__label" comment="Label of Settings language preference in Other">Agordojn lingvo</string>
|
||||
<string name="pref__other__show_app_icon__label" comment="Label of Show app icon preference in Other">Montri aplikaĵon ikonon en aplikaĵolanĉilo</string>
|
||||
<string name="pref__other__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Other for Android 10+">Ĉiam ŝaltata en Android 10+ pro sistemaj restriktoj</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Pri</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Aplikaĵo bildeto de FlorisBoard</string>
|
||||
@@ -312,12 +370,15 @@
|
||||
<string name="about__privacy_policy__summary" comment="Preference summary">La privateca politiko de tiu projekto</string>
|
||||
<string name="about__project_license__title" comment="Preference title">Projekton permesilo</string>
|
||||
<string name="about__project_license__error_license_text_failed" comment="Error text for license text loading failure">Eraro: Fiaskis elŝuti la permesilan tekston.\n-> Kaŭzo: {error_message}</string>
|
||||
<string name="about__third_party_licenses__title" comment="Preference title">Tria-partaj permesiloj</string>
|
||||
<string name="about__third_party_licenses__summary" comment="Preference summary">Permesiloj de la tria-partaj bibliotekoj enhavata en tiu apo</string>
|
||||
<!-- Setup UI strings -->
|
||||
<string name="setup__title" comment="Title of Setup">Bonvenon!</string>
|
||||
<string name="setup__footer__privacy_policy" comment="Privacy policy label for URL">Privateca politiko</string>
|
||||
<string name="setup__footer__repository" comment="Repository label for URL">Deponejo</string>
|
||||
<string name="setup__enable_ime__open_settings_btn">Malfermi sistemajn agordojn</string>
|
||||
<string name="setup__select_ime__switch_keyboard_btn">Ŝanĝi klavaron</string>
|
||||
<string name="setup__grant_notification_permission__title">Permesi kraŝajn raportajn sciigojn</string>
|
||||
<string name="setup__grant_notification_permission__btn">Permesi</string>
|
||||
<string name="setup__finish_up__title">Plenumi</string>
|
||||
<string name="setup__finish_up__finish_btn">Komenci agordi</string>
|
||||
@@ -327,6 +388,7 @@
|
||||
<string name="backup_and_restore__back_up__summary">Krei savkopion de la agordoj kaj personecigoj</string>
|
||||
<string name="backup_and_restore__back_up__destination">Elektu kie elporti la savkopion</string>
|
||||
<string name="backup_and_restore__back_up__destination_file_sys">Loka dosiersistemo</string>
|
||||
<string name="backup_and_restore__back_up__destination_share_intent">Tria-parta apo per kunhaviga menuo</string>
|
||||
<string name="backup_and_restore__back_up__files">Elektu kion estos savatan</string>
|
||||
<string name="backup_and_restore__back_up__files_jetpref_datastore">Agordoj</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_keyboard">Klavaraj etendaĵoj</string>
|
||||
@@ -351,6 +413,7 @@
|
||||
<string name="backup_and_restore__restore__failure">Fiaskis restaŭri datumojn: {error_message}</string>
|
||||
<!-- Crash Dialog strings -->
|
||||
<string name="crash_dialog__title" comment="Title of crash dialog">Erarojn raporto de FlorisBoard</string>
|
||||
<string name="crash_dialog__description" comment="Description of crash dialog">Pardonu la ĝeno, FlorisBoard kraŝis kaŭze de neatendita eraro.</string>
|
||||
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">Kopii al sistema tondujo</string>
|
||||
<string name="crash_dialog__copy_to_clipboard_success" comment="Label of Copy to clipboard success message in crash dialog">Kopiita al sistema tondujo</string>
|
||||
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Fermi</string>
|
||||
@@ -361,7 +424,7 @@
|
||||
<!-- Clipboard strings -->
|
||||
<string name="clipboard__header_title">Tondujo</string>
|
||||
<string name="clipboard__disabled__title">Tonduja historio estas nun malŝaltita</string>
|
||||
<string name="clipboard__disabled__message">{app_name}on tondujan historio ebligas vin rapide konservi kaj aliri la tekstojn kaj la bildojn ke vi kopias, kun la eblo de alpingli erojn, agordi aŭtomatan elviŝadon kaj difini maksimumon da konservitaj eroj.</string>
|
||||
<string name="clipboard__disabled__message">{app_name}on tonduja historio ebligas vin rapide konservi kaj aliri la tekstojn kaj la bildojn ke vi kopias, kun la eblo de alpingli erojn, agordi aŭtomatan elviŝadon kaj difini maksimumon da konservitaj eroj.</string>
|
||||
<string name="clipboard__disabled__enable_button">Ŝalti tondujan historion</string>
|
||||
<string name="clipboard__empty__title">Via tondujo estas malplena</string>
|
||||
<string name="clipboard__empty__message">Kiam vi kopios tekstojn aŭ bildojn, ilin aperos ĉi tie.</string>
|
||||
@@ -391,12 +454,19 @@
|
||||
<string name="pref__clipboard__sync_from_system_clipboard__summary">Sisteman tondujon ĝisdatigoj ankaŭ ĝisdatigos Floris tondujon</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__label">Sinkronigi al sistema tondujo</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__summary">Floris tondujon ĝisdatigoj ankaŭ ĝisdatigos sisteman tondujon</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">Tondujaj sugestoj</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__label" comment="Preference title">Tondujan enhavon sugestoj</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__summary" comment="Preference summary">Sugesti antaŭe kopiitan tondujan enhavon</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__summary` and is the first part">Limigi tondujajn sugestojn je</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__label` and is the second part">eroj kopiitaj dum la lastaj {v} s</string>
|
||||
<string name="pref__clipboard__group_clipboard_history__label">Tonduja historio</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__label">Ŝalti tondujan historion</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">Memori tondujajn erojn por rapida alireblo</string>
|
||||
<string name="pref__clipboard__clean_up_old__label">Elviŝi malnovajn erojn</string>
|
||||
<string name="pref__clipboard__clean_up_after__label">Elviŝi malnovajn erojn post:</string>
|
||||
<string name="pref__clipboard__limit_history_size__label">Limitigi la grandon de la historio</string>
|
||||
<string name="pref__clipboard__auto_clean_sensitive__label">Aŭtomate elviŝi kaŝendaj eroj</string>
|
||||
<string name="pref__clipboard__auto_clean_sensitive_after__label">Aŭtomate elviŝi kaŝendaj eroj post</string>
|
||||
<string name="pref__clipboard__limit_history_size__label">Limigi la grandon de la historio</string>
|
||||
<string name="pref__clipboard__max_history_size__label">Maksimuma grando historion</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__label">Viŝi lastan eron efikas sur historion</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__summary">Viŝi lastan tondujan eron ankaŭ forigas la lastan historian enigaĵon</string>
|
||||
@@ -406,10 +476,14 @@
|
||||
</string>
|
||||
<string name="send_to_clipboard__description__copied_image_to_clipboard">Malsupra bildo kopiita al tondujo.</string>
|
||||
<!-- Devtools strings -->
|
||||
<string name="devtools__title" comment="Title of Devtools screen. Translators: treat this string as 'Developer tools' for translation, except a similar short term is available for your language.">Programistiloj</string>
|
||||
<string name="devtools__enabled__label" comment="Label of Enable developer tools in Devtools">Ŝalti programistilojn</string>
|
||||
<string name="devtools__title" comment="Title of Devtools screen. Translators: treat this string as 'Developer tools' for translation, except a similar short term is available for your language.">Programiloj</string>
|
||||
<string name="devtools__enabled__label" comment="Label of Enable developer tools in Devtools">Aktivigi programilojn</string>
|
||||
<string name="devtools__enabled__summary" comment="Summary of Enable developer tools in Devtools">Iloj specife fasonitaj por sencimigo kaj problemsolvo</string>
|
||||
<string name="devtools__android_settings_global__title" comment="Title of Android settings (global) screen">Ĝeneralaj Androidon agordoj</string>
|
||||
<string name="devtools__group_android__title" comment="Title of Android group in Devtools">Androidon sistemaj iloj</string>
|
||||
<string name="devtools__android_settings_global__title" comment="Title of Android settings (global) screen">Ĝeneralaj agordoj Androidon</string>
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Sekurecaj agordoj Androidon</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Sistemaj agordoj Androidon</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Sistemaj lokaĵoj</string>
|
||||
<string name="devtools__debuglog__loading">Ŝargiĝante…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Aldonaĵoj & Etendaĵoj</string>
|
||||
@@ -417,11 +491,17 @@
|
||||
<string name="ext__list__ext_keyboard">Klavaraj etendaĵoj</string>
|
||||
<string name="ext__list__ext_languagepack">Lingvaj pakaj etendaĵoj</string>
|
||||
<string name="ext__meta__authors">Aŭtoroj</string>
|
||||
<string name="ext__meta__components">Kunligataj komponentoj</string>
|
||||
<string name="ext__meta__components_theme">Kunligataj etosoj</string>
|
||||
<string name="ext__meta__components_language_pack">Kunligataj lingvaj pakoj</string>
|
||||
<string name="ext__meta__components_none_found">Tiu etendaĵa arkivo enhavas neniun kunligatajn komponentojn.</string>
|
||||
<string name="ext__meta__description">Priskribo</string>
|
||||
<string name="ext__meta__homepage">Ĉefpaĝo</string>
|
||||
<string name="ext__meta__id">Identigilo</string>
|
||||
<string name="ext__meta__keywords">Ŝlosilvortoj</string>
|
||||
<string name="ext__meta__label">Etikedo</string>
|
||||
<string name="ext__meta__license">Permesilo</string>
|
||||
<string name="ext__meta__maintainers">Tenadantoj</string>
|
||||
<string name="ext__meta__maintainers_by">De: {maintainers}</string>
|
||||
<string name="ext__meta__title">Titolo</string>
|
||||
<string name="ext__meta__version">Versio</string>
|
||||
@@ -433,14 +513,17 @@
|
||||
<string name="ext__editor__title_edit_any">Redakti etendaĵon</string>
|
||||
<string name="ext__editor__title_edit_keyboard">Redakti klavaran etendaĵon</string>
|
||||
<string name="ext__editor__title_edit_theme">Redakti etosan etendaĵon</string>
|
||||
<string name="ext__editor__metadata__title">Administri metadatumojn</string>
|
||||
<string name="ext__editor__metadata__title">Mastrumi metadatumojn</string>
|
||||
<string name="ext__editor__metadata__title_invalid">Malvalidaj metadatumoj</string>
|
||||
<string name="ext__editor__metadata__message_invalid">La metadatumoj de tiu etendaĵo estas malvalida, bonvolu kontroli la metadatumredaktilo por detaloj!</string>
|
||||
<string name="ext__editor__dependencies__title">Mastrumi dependaĵojn</string>
|
||||
<string name="ext__editor__files__title">Mastrumi arkivajn dosierojn</string>
|
||||
<string name="ext__editor__create_component__title">Krei komponanton</string>
|
||||
<string name="ext__editor__create_component__title_theme">Krei etoson</string>
|
||||
<string name="ext__editor__create_component__from_empty">Malplena</string>
|
||||
<string name="ext__editor__create_component__from_existing">El iu jam ekzistanta</string>
|
||||
<string name="ext__editor__edit_component__title">Redakti komponenton</string>
|
||||
<string name="ext__editor__edit_component__title_theme">Redakti etosan komponenton</string>
|
||||
<string name="ext__export__success">Sukcesa etendaĵon eksportado!</string>
|
||||
<string name="ext__export__failure">Fiaskis eksporti etendaĵon: {error_message}</string>
|
||||
<string name="ext__import__success">Sukcesa etendaĵon enportado!</string>
|
||||
@@ -449,6 +532,8 @@
|
||||
<string name="ext__import__ext_keyboard" comment="Title of Importer screen for keyboard extension import">Importi klavaran etendaĵon</string>
|
||||
<string name="ext__import__ext_theme" comment="Title of Importer screen for theme extension import">Importi etosan etendaĵon</string>
|
||||
<string name="ext__import__ext_languagepack" comment="Title of Importer screen for language pack extension import">Importi lingvajn pakajn etendaĵojn</string>
|
||||
<string name="ext__import__file_skip" comment="Label when a file cannot be imported in the current context. The actual reason string is in a separate text view below this string.">Dosiero ne povas esti importata. Kialo:</string>
|
||||
<string name="ext__import__file_skip_unsupported" comment="Reason string when file is unsupported">Nesubtenata aŭ nerekonata dosiera tipo.</string>
|
||||
<string name="ext__import__file_skip_ext_not_supported" comment="Reason string when file is loaded in incorrect context">Atendis aŭdiovidaĵan dosieron (bildon, sonaĵon, tiparon, ktp) sed trovis etendaĵan arkivon.</string>
|
||||
<string name="ext__import__file_skip_media_not_supported" comment="Reason string when file is loaded in incorrect context">Atendis etendaĵan arkivon sed trovis aŭdiovidaĵan dosieron (bildon, sonaĵon, tiparon, ktp).</string>
|
||||
<string name="ext__import__error_unexpected_exception" comment="Label when an error occurred during import. The error message will be appended below this text view">Neatendita eraro okazis dum enportado. Tiuj detaloj estis provizataj:</string>
|
||||
@@ -456,16 +541,27 @@
|
||||
<string name="ext__validation__error_package_name">Pakaĵon nomo ne kongruas kun regulesprimo {id_regex}</string>
|
||||
<string name="ext__validation__enter_version">Bonvolu enigi version</string>
|
||||
<string name="ext__validation__enter_title">Bonvolu enigi titolon</string>
|
||||
<string name="ext__validation__enter_maintainer">Bonvolu enigi almenaŭ unu validan tendanton</string>
|
||||
<string name="ext__validation__enter_license">Bonvolu enigi permesilan identigilon</string>
|
||||
<string name="ext__validation__enter_component_id">Bonvolu enigi komponantan identigilon</string>
|
||||
<string name="ext__validation__error_component_id">Bonvolu enigi komponanton konigilo kongruantan kun {component_id_regex}</string>
|
||||
<string name="ext__validation__enter_component_label">Bonvolu enigi komponantan etikedon</string>
|
||||
<string name="ext__validation__error_author">Bonvolu enigi almenaŭ unu validan aŭtoron</string>
|
||||
<string name="ext__validation__error_stylesheet_path_blank">La stilfolia vojo ne povas esti malplena</string>
|
||||
<string name="ext__validation__error_stylesheet_path">Bonvolu enigi validan stilfolian vojon kongruantan kun {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Bonvolu enigi variablan nomon</string>
|
||||
<string name="ext__validation__error_property">Bonvolu enigi validan nomon de variablo kongruantan kun {variable_name_regex}</string>
|
||||
<string name="ext__validation__enter_color">Bonvolu enigi koloran ĉenon</string>
|
||||
<string name="ext__validation__error_color">Bonvolu enigi validan koloran ĉenon</string>
|
||||
<string name="ext__validation__enter_dp_size">Bonvolu enigi grandon je dp</string>
|
||||
<string name="ext__validation__enter_valid_number">Bonvolu enigi validan nombron</string>
|
||||
<string name="ext__validation__enter_positive_number">Bonvolu enigi pozitivan nombron (>=0)</string>
|
||||
<string name="ext__validation__enter_percent_size">Bonvolu enigi grandon je %</string>
|
||||
<string name="ext__validation__enter_number_between_0_100">Bonvolu enigi pozitivan nombron inter 0 kaj 100</string>
|
||||
<string name="ext__update_box__internet_permission_hint">Tiu apo ne havas retpermeson, do instalitajn etendaĵojn ĝisdatigoj endas esti serĉataj mane.</string>
|
||||
<string name="ext__update_box__search_for_updates">Serĉi ĝisdatigojn</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">Administri la {extensions}</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">Ĉiuj taskoj rilataj al importado, eksportado, kreado, personecigo, kaj forigo etendaĵojn povas esti mastrumata per la centralizita etendaĵa mastrumilo.</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Iri al {ext_home_title}</string>
|
||||
<string name="ext__home__info">Vi povas elŝuti kaj instali etendaĵojn el la FlorisBoard Aldonaĵejo aŭ enporti iun ajn etendaĵan dosieron ke vi elŝutis el la interreto.</string>
|
||||
<string name="ext__home__visit_store">Viziti Aldonaĵejon</string>
|
||||
@@ -478,13 +574,15 @@
|
||||
<string name="action__back_up">Savkopii</string>
|
||||
<string name="action__cancel">Nuligi</string>
|
||||
<string name="action__create">Krei</string>
|
||||
<string name="action__default">Norma</string>
|
||||
<string name="action__default">Norme</string>
|
||||
<string name="action__delete">Forigi</string>
|
||||
<string name="action__delete_confirm_title">Konfirmi forigon</string>
|
||||
<string name="action__delete_confirm_message">Ĉu vi certe volas forigi \"{name}\"? Tiu ago ne povos esti malfarata post sia efektivigo.</string>
|
||||
<string name="action__delete_confirm_message">Ĉu vi certe volas forigi \"{name}\"? Tiu ago ne povos esti malfarata post sia efektiviĝo.</string>
|
||||
<string name="action__reset_confirm_title">Konfirmi elviŝon</string>
|
||||
<string name="action__reset_confirm_message">Ĉu vi certe volas elviŝi \"{name}\"? Tiu ago ne povos esti malfarata post sia efektiviĝo.</string>
|
||||
<string name="action__discard">Forĵeti</string>
|
||||
<string name="action__discard_confirm_title">Ŝanĝoj nekonservitaj</string>
|
||||
<string name="action__discard_confirm_message">Ĉu vi certe volas forĵeti vian nekonservitajn ŝanĝojn? Tiu ago ne povos esti malfarata post sia efektivigo.</string>
|
||||
<string name="action__discard_confirm_message">Ĉu vi certe volas forĵeti vian nekonservitajn ŝanĝojn? Tiu ago ne povos esti malfarata post sia efektiviĝo.</string>
|
||||
<string name="action__edit">Redakti</string>
|
||||
<string name="action__export">Elporti</string>
|
||||
<string name="action__import">Enporti</string>
|
||||
@@ -526,8 +624,6 @@
|
||||
<string name="enum__candidates_display_mode__dynamic" comment="Enum value label">Dinamika larĝo</string>
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">Dinamika larĝo & rulumebla</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_double_tap" comment="Enum value label">Enŝalti fiksan majuskligon per duobla frapetado sur la uskla klavo</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">Deksesuma</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">Ruĝa Verda Blua Alfo</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">Ĉiam montri</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">Ĉiam montri la klavaron ferminte iun ajn redaktilan dialogujon</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">Neniam montri</string>
|
||||
@@ -573,12 +669,23 @@
|
||||
<string name="enum__incognito_mode__force_off" comment="Enum value label">Ĉiam malŝaltata</string>
|
||||
<string name="enum__incognito_mode__force_on" comment="Enum value label">Ĉiam ŝaltata</string>
|
||||
<string name="enum__incognito_mode__dynamic_on_off" comment="Enum value label">Dinamika ŝalta stato</string>
|
||||
<string name="enum__input_feedback_activation_mode__audio_respect_system_settings" comment="Enum value label">Dinamike soni je enigoj, laŭ sistemaj agordoj</string>
|
||||
<string name="enum__input_feedback_activation_mode__audio_ignore_system_settings" comment="Enum value label">Ĉiam soni je enigoj, senrigarde al sistemaj agordoj</string>
|
||||
<string name="enum__input_feedback_activation_mode__haptic_respect_system_settings" comment="Enum value label">Dinamike vibri je enigoj, laŭ sistemaj agordoj</string>
|
||||
<string name="enum__input_feedback_activation_mode__haptic_ignore_system_settings" comment="Enum value label">Ĉiam vibri je enigoj, senrigarde al sistemaj agordoj</string>
|
||||
<string name="enum__input_shift_state__unshifted" comment="Enum value label">Malmajuskligita</string>
|
||||
<string name="enum__input_shift_state__shifted_manual" comment="Enum value label">Majuskligita (mane)</string>
|
||||
<string name="enum__input_shift_state__shifted_automatic" comment="Enum value label">Majuskligita (aŭtomate)</string>
|
||||
<string name="enum__input_shift_state__caps_lock" comment="Enum value label">Fiks. Maj.</string>
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Neniam montri</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Ĉiam montri</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Dinamike montri</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Malvalidigita</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Maldekstramana moduso</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Dekstramana moduso</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Supre maldekstre</string>
|
||||
<string name="enum__shape_corner__top_end" comment="Enum value label">Supre dekstre</string>
|
||||
<string name="enum__shape_corner__bottom_end" comment="Enum value label">Sube dekstre</string>
|
||||
<string name="enum__shape_corner__bottom_start" comment="Enum value label">Supre maldekstre</string>
|
||||
<string name="enum__smartbar_layout__suggestions_only" comment="Enum value label">Nur sugestoj</string>
|
||||
<string name="enum__smartbar_layout__suggestions_only__description" comment="Enum value description">Montri nur la sugestojn-vicon, sen ia ajn agojn-vico/ŝaltilo aŭ fiksita ago</string>
|
||||
<string name="enum__smartbar_layout__actions_only" comment="Enum value label">Nur agoj</string>
|
||||
@@ -588,8 +695,11 @@
|
||||
<string name="enum__smartbar_layout__suggestions_actions_extended" comment="Enum value label">Sugestoj & Agoj plie</string>
|
||||
<string name="enum__smartbar_layout__suggestions_actions_extended__description" comment="Enum value description">Statika sugestojn-vico kaj aldona ŝaltebla agojn-vico, kun fiksita ago</string>
|
||||
<string name="enum__snygg_level__basic" comment="Enum value label">Baza</string>
|
||||
<string name="enum__snygg_level__basic__description" comment="Enum value description">Nur koloraj propraĵoj estas montritaj, propraĵoj kaj reguloj estas tradukitaj.</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Spertula</string>
|
||||
<string name="enum__snygg_level__developer" comment="Enum value label">Programisto</string>
|
||||
<string name="enum__snygg_level__advanced__description" comment="Enum value description">Ĉiuj koloraj propraĵoj estas montritaj, propraĵoj kaj reguloj estas tradukitaj.</string>
|
||||
<string name="enum__snygg_level__developer" comment="Enum value label">Programista</string>
|
||||
<string name="enum__snygg_level__developer__description" comment="Enum value description">Ĉiuj propraĵoj estas montritaj, propraĵoj kaj reguloj estas tiel montritaj, kiel skribitaj en la stilfolio mem.</string>
|
||||
<string name="enum__space_bar_mode__nothing" comment="Enum value label">Nenio</string>
|
||||
<string name="enum__space_bar_mode__current_language" comment="Enum value label">Aktuala lingvo</string>
|
||||
<string name="enum__space_bar_mode__space_bar_key" comment="Enum value label">␣</string>
|
||||
@@ -602,7 +712,7 @@
|
||||
<string name="enum__swipe_action__delete_characters_precisely" comment="Enum value label">Forigi signojn precize</string>
|
||||
<string name="enum__swipe_action__delete_word" comment="Enum value label">Forigi la vorton antaŭ la kursoron</string>
|
||||
<string name="enum__swipe_action__delete_words_precisely" comment="Enum value label">Forigi vortojn precize</string>
|
||||
<string name="enum__swipe_action__hide_keyboard" comment="Enum value label">Kaŝi klavaron</string>
|
||||
<string name="enum__swipe_action__hide_keyboard" comment="Enum value label">Kaŝi la klavaron</string>
|
||||
<string name="enum__swipe_action__insert_space" comment="Enum value label">Enigi spaceton</string>
|
||||
<string name="enum__swipe_action__move_cursor_up" comment="Enum value label">Movi la kursoron supren</string>
|
||||
<string name="enum__swipe_action__move_cursor_down" comment="Enum value label">Movi la kursoron suben</string>
|
||||
@@ -628,8 +738,8 @@
|
||||
<string name="enum__theme_mode__follow_system" comment="Enum value label">Laŭ operaciumo</string>
|
||||
<string name="enum__theme_mode__follow_time" comment="Enum value label">Laŭ tempo</string>
|
||||
<string name="enum__utility_key_action__switch_to_emojis" comment="Enum value label">Iri al emoĝiojn</string>
|
||||
<string name="enum__utility_key_action__switch_language" comment="Enum value label">Baskuli lingvon</string>
|
||||
<string name="enum__utility_key_action__switch_keyboard_app" comment="Enum value label">Ŝalti klavara aplikaĵo</string>
|
||||
<string name="enum__utility_key_action__switch_language" comment="Enum value label">Baskuligi lingvon</string>
|
||||
<string name="enum__utility_key_action__switch_keyboard_app" comment="Enum value label">Baskuligi al alia klavara aplikaĵo</string>
|
||||
<string name="enum__utility_key_action__dynamic_switch_language_emojis" comment="Enum value label">Dinamika: iri al emoĝiojn / ŝanĝi lingvon</string>
|
||||
<!-- Unit strings (symbols) -->
|
||||
<!-- Unit strings (written words) -->
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<string name="quick_actions_editor__subheader_sticky_action">Acción fijada ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Acciones dinámicas ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Acciones ocultas ({n})</string>
|
||||
<string name="select_subtype_panel__header">Selecciona subtipo</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">El modo incógnito está activo \n\n{app_name} no aprenderá palabras de tus entradas mientras este modo esté activo</string>
|
||||
<string name="incognito_mode__toast_after_disabled">El modo incógnito está deshabilitado por defecto</string>
|
||||
@@ -111,6 +112,7 @@
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">FlorisBoard no está seleccionado como método de entrada predeterminado. Haga clic aquí para solucionar este problema.</string>
|
||||
<string name="settings__localization__title" comment="Title of languages and Layout screen">Idiomas & Distribuciones</string>
|
||||
<string name="settings__localization__display_language_names_in__label" comment="Label of Display language names in preference">Muestra nombres de idiomas en</string>
|
||||
<string name="settings__localization__display_keyboard_labels_in_subtype_language" comment="Label of Display keyboard labels in subtype language preference">Mostrar las etiquetas del teclado en mismo idioma</string>
|
||||
<string name="settings__localization__group_subtypes__label" comment="Label of subtypes group">Subtipos</string>
|
||||
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">Añadir subtipo</string>
|
||||
<string name="settings__localization__language_pack_title" comment="Title of the language pack manager screen for managing installed and custom language packs">Administrar paquetes de idioma instalados</string>
|
||||
@@ -151,7 +153,6 @@
|
||||
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Hora de puesta de sol</string>
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Tema claro</string>
|
||||
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Tema oscuro</string>
|
||||
<string name="pref__theme__theme_accent_color__label" comment="Label of accent color preference in Theme">Colores del énfasis (Temas Material You) </string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Gestionar temas instalados</string>
|
||||
<string name="pref__theme__source_assets" comment="Label for the theme source field">Recursos de aplicación de FlorisBoard</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Almacenamiento interno</string>
|
||||
@@ -160,13 +161,11 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Elegir tema oscuro</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">Editor de ajuste fino</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">Nivel de edición</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Mostrar colores como</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Mostrar teclado después de diálogos</string>
|
||||
<string name="settings__theme_editor__add_rule">Añadir regla</string>
|
||||
<string name="settings__theme_editor__edit_rule">Editar regla</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Esta hoja de estilo no tiene reglas definidas. Agregue una regla para comenzar a personalizar esta hoja de estilo.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Esta regla de hoja de estilo ya está definida.</string>
|
||||
<string name="settings__theme_editor__rule_element">Elemento destino</string>
|
||||
<string name="settings__theme_editor__rule_codes">Códigos de clave destino</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grupos</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Cambiar estados</string>
|
||||
@@ -194,18 +193,11 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">Es tema oscuro</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">Es sin borde</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">Ruta de la hoja de estilo</string>
|
||||
<string name="snygg__rule_element__defines">Variables</string>
|
||||
<string name="snygg__rule_element__defines_description">Defina variables dentro de esta regla para reutilizar colores o tamaños comunes en su hoja de estilos.</string>
|
||||
<string name="snygg__rule_element__keyboard">Ventana de teclado</string>
|
||||
<string name="snygg__rule_element__key">Tecla</string>
|
||||
<string name="snygg__rule_element__key_hint">Tecla sugerida</string>
|
||||
<string name="snygg__rule_element__key_popup">Tecla emergente</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Encabezado del portapapeles</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Ítem de portapapeles</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Ítem de portapapeles emergente</string>
|
||||
<string name="snygg__rule_element__emoji_key">Tecla de emoji</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">Ventana emergente de la tecla Emoji</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Pestaña de emojis</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Disposición de la entrada del paisaje</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Campo de entrada en paisaje</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Acción de entrada apaisada</string>
|
||||
@@ -228,12 +220,9 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Palabra candidata de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Clip candidato de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">Espaciado candidato de barra inteligente</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Barra de navegación de sistema</string>
|
||||
<string name="snygg__rule_selector__pressed">Presionado</string>
|
||||
<string name="snygg__rule_selector__focus">Focalizado</string>
|
||||
<string name="snygg__rule_selector__disabled">Deshabilitado</string>
|
||||
<string name="snygg__property_name__width">Anchura</string>
|
||||
<string name="snygg__property_name__height">Altura</string>
|
||||
<string name="snygg__property_name__background">Fondo</string>
|
||||
<string name="snygg__property_name__foreground">Primer plano</string>
|
||||
<string name="snygg__property_name__border_color">Color de borde</string>
|
||||
@@ -242,7 +231,6 @@
|
||||
<string name="snygg__property_name__font_family">Familia de fuente</string>
|
||||
<string name="snygg__property_name__font_size">Tamaño de fuente</string>
|
||||
<string name="snygg__property_name__font_style">Estilo de fuente</string>
|
||||
<string name="snygg__property_name__font_variant">Variante de fuente</string>
|
||||
<string name="snygg__property_name__font_weight">Ancho de fuente</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Elevación de sombra</string>
|
||||
<string name="snygg__property_name__shape">Forma</string>
|
||||
@@ -261,10 +249,10 @@
|
||||
<string name="snygg__property_name__var_shape">Forma común</string>
|
||||
<string name="snygg__property_name__var_shape_variant">Forma común (variante)</string>
|
||||
<string name="snygg__property_value__explicit_inherit">Heredar</string>
|
||||
<string name="snygg__property_value__defined_var">Referencia de Var</string>
|
||||
<string name="snygg__property_value__solid_color">Color sólido</string>
|
||||
<string name="snygg__property_value__material_you_light_color">Color Material You (claro)</string>
|
||||
<string name="snygg__property_value__material_you_dark_color">Color Material You (oscuro)</string>
|
||||
<string name="snygg__property_value__image_ref">Referencia de imagen</string>
|
||||
<string name="snygg__property_value__rectangle_shape">Forma rectangular</string>
|
||||
<string name="snygg__property_value__circle_shape">Forma circular</string>
|
||||
<string name="snygg__property_value__cut_corner_shape_dp">Forma de esquina recortada (dp)</string>
|
||||
@@ -274,7 +262,6 @@
|
||||
<string name="snygg__property_value__dp_size">Tamaño (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">Tamaño (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">Tamaño (%)</string>
|
||||
<string name="snygg__property_value__defined_var">Referencia de Var</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Sonidos & Vibración</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Respuesta de audio / Sonidos</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Habilitar respuesta de audio</string>
|
||||
@@ -349,11 +336,8 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Muestra sugerencias mientras escribe</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Modo de visualización de sugerencias</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Bloquear posibles palabras ofensivas</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Sugerencias del contenido del portapapeles</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Sugerir el contenido del portapapeles copiado anteriormente</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Limitar sugerencias del portapapeles a</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">Elementos copiados dentro de los últimos {v} s</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">Muestra sugerencias inline ofrecidas por servicios de autocompletado</string>
|
||||
<string name="pref__suggestion__incognito_mode__label" comment="Label of Incognito mode preference in Typing">Modo incógnito</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Correcciones</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Mayúsculas automáticas</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Poner en mayúsculas las palabras según el contexto de entrada actual</string>
|
||||
@@ -427,18 +411,17 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Pulsación larga de la tecla de borrado</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Velocidad del deslizamiento</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Distancia del deslizamiento</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Avanzado</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Ajustes del tema</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Predeterminado del sistema (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Claro</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Oscuro</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Oscuro</string>
|
||||
<string name="pref__advanced__settings_accent_color__label" comment="Label of accent color preference in Advanced">Ajustes de los colores de énfasis
|
||||
<string name="settings__other__title" comment="Title of Other settings">Otro</string>
|
||||
<string name="pref__other__settings_theme__label" comment="Label of Settings theme preference in Other">Ajustes del tema</string>
|
||||
<string name="pref__other__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Other">Predeterminado del sistema (AMOLED)</string>
|
||||
<string name="pref__other__settings_theme__light" comment="Possible value of Settings theme preference in Other">Claro</string>
|
||||
<string name="pref__other__settings_theme__dark" comment="Possible value of Settings theme preference in Other">Oscuro</string>
|
||||
<string name="pref__other__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Other">AMOLED Oscuro</string>
|
||||
<string name="pref__other__settings_accent_color__label" comment="Label of accent color preference in Other">Ajustes del color del énfasis
|
||||
</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Idioma de ajustes</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Mostrar icono de la aplicación en el launcher</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Habilitado siempre en Android 10+ debido a restricciones del sistema</string>
|
||||
<string name="pref__advanced__incognito_mode__label" comment="Label of Incognito mode preference in Advanced">Modo incógnito</string>
|
||||
<string name="pref__other__settings_language__label" comment="Label of Settings language preference in Other">Ajustes del idioma</string>
|
||||
<string name="pref__other__show_app_icon__label" comment="Label of Show app icon preference in Other">Mostrar el icono de la aplicación en el launcher</string>
|
||||
<string name="pref__other__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Other for Android 10+">Siempre habilitado en Android 10 y superior debido a las restricciones del sistema</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Acerca de</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Icono de la aplicación de FlorisBoard</string>
|
||||
@@ -560,6 +543,11 @@
|
||||
<string name="pref__clipboard__sync_from_system_clipboard__summary">Las actualizaciones en el portapapeles del sistema también actualizan el portapapeles de Floris</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__label">Sincronizar al portapapeles del sistema</string>
|
||||
<string name="pref__clipboard__sync_to_system_clipboard__summary">Las actualizaciones del portapapeles de Floris también actualizan el portapapeles del sistema</string>
|
||||
<string name="pref__clipboard__group_clipboard_suggestion__label">Sugerencias del portapapeles</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__label" comment="Preference title">Sugerencias del contenido del portapapeles</string>
|
||||
<string name="pref__clipboard__suggestion_enabled__summary" comment="Preference summary">Sugerir contenido del portapapeles copiado anteriormente</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__summary` and is the first part">Limitar las sugerencias del portapapeles a</string>
|
||||
<string name="pref__clipboard__suggestion_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__clipboard__suggestion_timeout__label` and is the second part">Elementos copiados en los últimos {v} s</string>
|
||||
<string name="pref__clipboard__group_clipboard_history__label">Historial del portapapeles</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__label">Habilitar historial de portapapeles</string>
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">Conservar elementos del portapapeles para acceso rápido</string>
|
||||
@@ -679,7 +667,6 @@
|
||||
<string name="ext__validation__error_stylesheet_path">Por favor, introduzca un directorio válido a la hoja de estilos, que coincida con {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Por favor, introduzca un nombre de variable</string>
|
||||
<string name="ext__validation__error_property">Por favor, introduzca un nombre de variable que coincida con {variable_name_regex}</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">Por convención, los nombres de variables en FlorisCSS inician con dos guiones (--)</string>
|
||||
<string name="ext__validation__enter_color">Por favor, introduzca una cadena de color</string>
|
||||
<string name="ext__validation__error_color">Por favor, introduzca una cadena de color válida</string>
|
||||
<string name="ext__validation__enter_dp_size">Por favor, introduzca un tamaño dp</string>
|
||||
@@ -755,8 +742,6 @@
|
||||
<string name="enum__candidates_display_mode__dynamic_scrollable" comment="Enum value label">Ancho dinámico & desplazable</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_double_tap" comment="Enum value label">Permitr Bloq May haciendo doble toque en mayúscula</string>
|
||||
<string name="enum__capitalization_behavior__capslock_by_cycle" comment="Enum value label">Cambiar modo de capitalización cada vez que se pulsa la tecla Mayús</string>
|
||||
<string name="enum__display_colors_as__hex8" comment="Enum value label">Hexadecimal</string>
|
||||
<string name="enum__display_colors_as__rgba" comment="Enum value label">Rojo Verde Azul Alfa</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always" comment="Enum value label">Mostrar siempre</string>
|
||||
<string name="enum__display_kbd_after_dialogs__always__description" comment="Enum value description">Mostrar siempre el teclado al cerrar un editor de diálogo</string>
|
||||
<string name="enum__display_kbd_after_dialogs__never" comment="Enum value label">No mostrar nunca</string>
|
||||
@@ -825,7 +810,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">No mostrar nunca</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Mostrar siempre</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Mostrar dinámicamente</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Apagado</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Modo para zurdos</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Modo para diestros</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Inicio superior</string>
|
||||
|
||||
@@ -111,12 +111,10 @@
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">انتخاب تم شب</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">ویرایشگر دقیق</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">سطح ویرایشگر</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">رنگ را مانند ... نشان بده</string>
|
||||
<string name="settings__theme_editor__add_rule">افزودن قانون</string>
|
||||
<string name="settings__theme_editor__edit_rule">ویرایش قانون</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">این شیوه نامه قانون تعریف شده ای ندارد. یک قانون اضافه کنید تا این شیوه نامه را شخصی سازی کنید.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">این قانون شیوه نامه از قبل تعریف شده است.</string>
|
||||
<string name="settings__theme_editor__rule_element">مؤلفه مورد نظر</string>
|
||||
<string name="settings__theme_editor__rule_codes">کد کلیدهای مورد نظر</string>
|
||||
<string name="settings__theme_editor__rule_groups">گروه ها</string>
|
||||
<string name="settings__theme_editor__rule_selectors">انتخابگرها</string>
|
||||
@@ -141,16 +139,12 @@
|
||||
<string name="settings__theme_editor__property_value_shape_apply_for_all_corners">برای تمام گوشه ها اعمال کن</string>
|
||||
<string name="settings__theme_editor__property_value_color_dialog_title">ویرایش متن رنگ</string>
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">پس زمینه شب</string>
|
||||
<string name="snygg__rule_element__defines">متغیرها</string>
|
||||
<string name="snygg__rule_element__key">کلید</string>
|
||||
<string name="snygg__rule_element__key_hint">راهنما دکمه</string>
|
||||
<string name="snygg__rule_element__key_popup">کلید خود بازشونده</string>
|
||||
<string name="snygg__rule_element__clipboard_item">وسیله کلیپ بورد</string>
|
||||
<string name="snygg__rule_element__emoji_key">کلید ایموجی</string>
|
||||
<string name="snygg__rule_element__smartbar">اسمارتبار</string>
|
||||
<string name="snygg__property_name__font_size">اندازه نوشته</string>
|
||||
<string name="snygg__property_name__font_style">شکل نوشته</string>
|
||||
<string name="snygg__property_name__font_variant">نوع نوشته</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">صداها & لرزش</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">صدای بازخورد / صداها</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">فعالسازی صدای بازخورد</string>
|
||||
@@ -178,7 +172,6 @@
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">بالای صفحهکلید نمایش داده خواهند شد</string>
|
||||
<!-- Typing strings -->
|
||||
<string name="pref__suggestion__title" comment="Preference group title">پیشنهادات</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">پیشنهادات محتوای کلیپ بورد</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">تصحیح</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">حرف اول بزرگ به صورت خودکار</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">بزرگ کردن حرف اول بر اساس محتوای ورودی</string>
|
||||
@@ -228,14 +221,6 @@
|
||||
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">کشیدن دکمه پاک کردن به چپ</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">آستانه سرعت کشیدن</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">آستانه مسافت کشیدن</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">پیشرفته</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">تنظیمات زمینه</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">روشن</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">تاریک</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">تاریک AMOLED</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">زبان تنظیمات</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">قرار دادن آیکون برنامه در لانچر</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">همیشه فعال شده بخاطر محدودیت های سیستم عامل های اندروید 10 به بالا</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">درباره</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">آیکون برنامه فلوریس بورد</string>
|
||||
@@ -334,7 +319,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">هرگز نشان نده</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">همیشه نشان بده</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">به صورت پویا نشان بده</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">خاموش</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">حالت دست چپی</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">حالت دست راستی</string>
|
||||
<string name="enum__spelling_language_mode__use_system_languages" comment="Enum value label">استفاده از زبان سیستم</string>
|
||||
|
||||
@@ -83,7 +83,6 @@
|
||||
<string name="settings__theme_editor__edit_rule">Muokkaa sääntöä</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Tässä tyylisäännöstössä ei ole määritelty sääntöjä. Lisää sääntö aloittaaksesi tyylisäännöstön mukauttamisen.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Tämä tyylisäännöstön sääntö on jo määritelty.</string>
|
||||
<string name="settings__theme_editor__rule_element">Kohde-elementti</string>
|
||||
<string name="settings__theme_editor__rule_groups">Sääntöryhmät</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Valitsimet</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Käytä sääntöä kaikissa kohde-elementeissä.</string>
|
||||
@@ -98,22 +97,14 @@
|
||||
<string name="settings__theme_editor__component_meta_is_night_theme">On yöteema</string>
|
||||
<string name="settings__theme_editor__component_meta_is_borderless">On reunaton</string>
|
||||
<string name="settings__theme_editor__component_meta_stylesheet_path">Tyylisäännöstön polku</string>
|
||||
<string name="snygg__rule_element__defines">Muuttujat</string>
|
||||
<string name="snygg__rule_element__defines_description">Määrittele yleisiä värejä ja mittoja muuttujina tyylisäännöstössä käytettäväksi.</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Leikepöydän otsake</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Leikepöydän kohde</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Leikepöydän kohteen ponnahdusikkuna</string>
|
||||
<string name="snygg__rule_element__emoji_key">Emojipainike</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">Emojipainikkeen ponnahdusikkuna</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Emojivälilehti</string>
|
||||
<string name="snygg__rule_element__glide_trail">Pyyhkäisyn jälki</string>
|
||||
<string name="snygg__rule_element__one_handed_panel">Yksikätinen paneeli</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Järjestelmän navigointipalkki</string>
|
||||
<string name="snygg__rule_selector__pressed">Painettu</string>
|
||||
<string name="snygg__rule_selector__focus">Kohdistettu</string>
|
||||
<string name="snygg__rule_selector__disabled">Pois käytöstä</string>
|
||||
<string name="snygg__property_name__width">Leveys</string>
|
||||
<string name="snygg__property_name__height">Korkeus</string>
|
||||
<string name="snygg__property_name__background">Tausta</string>
|
||||
<string name="snygg__property_name__foreground">Etuala</string>
|
||||
<string name="snygg__property_name__border_color">Reunuksen väri</string>
|
||||
@@ -122,7 +113,6 @@
|
||||
<string name="snygg__property_name__font_family">Kirjasinperhe</string>
|
||||
<string name="snygg__property_name__font_size">Kirjasimen koko</string>
|
||||
<string name="snygg__property_name__font_style">Kirjasintyyli</string>
|
||||
<string name="snygg__property_name__font_variant">Kirjasimen variantti</string>
|
||||
<string name="snygg__property_name__font_weight">Fontin vahvuus</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Varjon korostus</string>
|
||||
<string name="snygg__property_name__shape">Muoto</string>
|
||||
@@ -191,10 +181,6 @@
|
||||
<string name="pref__suggestion__enabled__summary" comment="Preference summary">Näyttää ehdotuksia kirjoittaessa</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Ehdotusten näkymä</string>
|
||||
<string name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">Estä mahdollisesti loukkaavat sanat</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Leikepöydän sisällön ehdotukset</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Ehdota leikepöydän sisältöjä</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__summary` and is the first part">Rajoita leikepöytäehdotuksia ajalle</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__summary" comment="Preference summary; Translators: This should form a sentence together with `pref__suggestion__clipboard_content_timeout__label` and is the second part">Kohteet, joita on koipioitu viimeisen {v}s aikana</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Korjaukset</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Automaattiset isot kirjaimet</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Automaattinen iso kirjain syöttökontekstin perusteella</string>
|
||||
@@ -265,15 +251,6 @@
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Poistopainikkeen pitkä painallus</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Pyyhkäisynopeuden kynnys</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Pyyhkäisyn pituuden kynnys</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Lisäasetukset</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Asetusten teema</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Järjestelmän oletus (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Vaalea</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Tumma</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Tumma</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Asetusten kieli</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Näytä sovellus sovellusvalikossa</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Aina käytössä Android 10+ järjestelmän rajoituksien vuoksi</string>
|
||||
<!-- About UI strings -->
|
||||
<string name="about__title" comment="Title of About activity">Tietoa</string>
|
||||
<string name="about__app_icon_content_description" comment="Content description of app icon in About">FlorisBoardin kuvake</string>
|
||||
@@ -457,7 +434,6 @@
|
||||
<string name="enum__landscape_input_ui_mode__never_show" comment="Enum value label">Älä näytä koskaan</string>
|
||||
<string name="enum__landscape_input_ui_mode__always_show" comment="Enum value label">Näytä aina</string>
|
||||
<string name="enum__landscape_input_ui_mode__dynamically_show" comment="Enum value label">Näytä dynaamisesti</string>
|
||||
<string name="enum__one_handed_mode__off" comment="Enum value label">Pois päältä</string>
|
||||
<string name="enum__one_handed_mode__start" comment="Enum value label">Vasemman käden tila</string>
|
||||
<string name="enum__one_handed_mode__end" comment="Enum value label">Oikean käden tila</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Lisäasetukset</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user