Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
166734757f | ||
|
|
97f401371f | ||
|
|
b012e5377b | ||
|
|
3b18dc33d8 | ||
|
|
d798f01576 | ||
|
|
55281bd7d6 | ||
|
|
88e9bde0a9 | ||
|
|
54d5a16761 | ||
|
|
701da50479 | ||
|
|
b43b6aa2d0 | ||
|
|
4279e9d100 | ||
|
|
e5bd979880 | ||
|
|
9a48169bf3 | ||
|
|
99cfd99815 | ||
|
|
e8f082d885 | ||
|
|
b63f475a8c | ||
|
|
e183f10969 | ||
|
|
c1e624b9a0 | ||
|
|
2d87d0e4d3 | ||
|
|
bcf1bffc24 | ||
|
|
f388e8811e | ||
|
|
7ededa6293 | ||
|
|
7d9e1cf2b5 | ||
|
|
299f581609 | ||
|
|
c38d4ed90b | ||
|
|
647bc659d7 | ||
|
|
61eb09e611 | ||
|
|
1a4118d29a | ||
|
|
48655b3771 | ||
|
|
17649c44bf | ||
|
|
7cbb19ddcb | ||
|
|
e13ac7c689 | ||
|
|
941733cdc0 | ||
|
|
a25289a856 | ||
|
|
7bcfeca872 | ||
|
|
240ebc499a | ||
|
|
831882f419 | ||
|
|
e0e5259b4c | ||
|
|
33cd2b5d01 | ||
|
|
d3dda86966 | ||
|
|
59aa5cdb33 | ||
|
|
d26e820492 | ||
|
|
b8b1b04c7e | ||
|
|
26b4acc894 | ||
|
|
12c4220544 | ||
|
|
5fc4f5ba60 | ||
|
|
03ea9bcb76 | ||
|
|
a04c44df98 | ||
|
|
b1431c7e51 | ||
|
|
c09719ffd6 | ||
|
|
16149d95a1 | ||
|
|
658e43da9c | ||
|
|
66ddb451ab | ||
|
|
f135513f3e | ||
|
|
322dfa717b | ||
|
|
bfe7852bdf | ||
|
|
45fe2f311e | ||
|
|
f73daa2b00 | ||
|
|
4e8ff9ec14 | ||
|
|
a96fc84fc1 | ||
|
|
e62ddc37dd | ||
|
|
06cfa34a4b | ||
|
|
ef849dfefd | ||
|
|
091d43520e | ||
|
|
95b6b1bbf9 | ||
|
|
021014e870 | ||
|
|
aaa4fbae7a | ||
|
|
78b645d820 | ||
|
|
61bd6752e3 | ||
|
|
e4e10f5c72 |
@@ -31,8 +31,8 @@ android {
|
||||
applicationId = "dev.patrickgold.florisboard"
|
||||
minSdk = 23
|
||||
targetSdk = 31
|
||||
versionCode = 75
|
||||
versionName = "0.3.14"
|
||||
versionCode = 80
|
||||
versionName = "0.3.15"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
@@ -128,9 +128,9 @@
|
||||
android:label="@string/crash_dialog__title"
|
||||
android:theme="@style/CrashDialogTheme"/>
|
||||
|
||||
<!-- Clipboard Image File Provider -->
|
||||
<!-- Clipboard Media File Provider -->
|
||||
<provider
|
||||
android:name="dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardImagesProvider"
|
||||
android:name="dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardMediaProvider"
|
||||
android:authorities="${applicationId}.provider.clipboard"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
|
||||
@@ -9,6 +9,18 @@
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
"currencySets": [
|
||||
{
|
||||
"id": "armenian_dram",
|
||||
"label": "Armenian dram (֏)",
|
||||
"slots": [
|
||||
{ "code": 1423, "label": "֏" },
|
||||
{ "code": 36, "label": "$" },
|
||||
{ "code": 8364, "label": "€" },
|
||||
{ "code": 162, "label": "¢" },
|
||||
{ "code": 163, "label": "£" },
|
||||
{ "code": 165, "label": "¥" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "azerbaijani_manat",
|
||||
"label": "Azerbaijani manat (₼)",
|
||||
|
||||
@@ -17,6 +17,26 @@
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:arabic"
|
||||
},
|
||||
{
|
||||
"id": "western_armenian",
|
||||
"label": "Armenian (Western)",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:armenian"
|
||||
},
|
||||
{
|
||||
"id": "eastern_armenian",
|
||||
"label": "Armenian (Eastern)",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:armenian"
|
||||
},
|
||||
{
|
||||
"id": "azerbaijani",
|
||||
"label": "Azerbaijani",
|
||||
"authors": [ "nijatismayilzada" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "azerty",
|
||||
"label": "AZERTY",
|
||||
@@ -72,6 +92,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "colemak_dh",
|
||||
"label": "ColemakDH",
|
||||
"authors": [ "blucin" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "danish",
|
||||
"label": "Danish (QWERTY)",
|
||||
@@ -109,6 +135,12 @@
|
||||
"authors": [ "mahmoudk1000" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "german2",
|
||||
"label": "German (GBoard)",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "greek",
|
||||
"label": "Ελληνικά",
|
||||
@@ -223,6 +255,13 @@
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian"
|
||||
},
|
||||
{
|
||||
"id": "persian2",
|
||||
"label": "Persian2",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl",
|
||||
"modifier": "org.florisboard.layouts:persian2"
|
||||
},
|
||||
{
|
||||
"id": "qwerty",
|
||||
"label": "QWERTY",
|
||||
@@ -346,6 +385,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "armenian",
|
||||
"label": "Armenian",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "arabic",
|
||||
"label": "Arabic",
|
||||
@@ -387,6 +432,12 @@
|
||||
"label": "Persian",
|
||||
"authors": [ "PHELAT" ],
|
||||
"direction": "rtl"
|
||||
},
|
||||
{
|
||||
"id": "persian2",
|
||||
"label": "Persian2",
|
||||
"authors": [ "M-Koushan" ],
|
||||
"direction": "rtl"
|
||||
}
|
||||
],
|
||||
"extension": [
|
||||
@@ -540,6 +591,13 @@
|
||||
}
|
||||
],
|
||||
"symbols": [
|
||||
{
|
||||
"id": "armenian",
|
||||
"label": "Armenian",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:armenian"
|
||||
},
|
||||
{
|
||||
"id": "cjk",
|
||||
"label": "CJK",
|
||||
@@ -592,6 +650,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "armenian",
|
||||
"label": "Armenian",
|
||||
"authors": [ "PJTSearch" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "cjk",
|
||||
"label": "CJK",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 105, "label": "i" },
|
||||
"upper": { "code": 304, "label": "İ" }
|
||||
},
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 287, "label": "ğ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 305, "label": "ı" },
|
||||
"upper": { "code": 73, "label": "I" }
|
||||
},
|
||||
{ "$": "auto_text_key", "code": 601, "label": "ə" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" },
|
||||
{ "$": "auto_text_key", "code": 231, "label": "ç" },
|
||||
{ "$": "auto_text_key", "code": 351, "label": "ş" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 59, "label": ";", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 58, "label": ":" }
|
||||
]
|
||||
} },
|
||||
"upper": { "code": 58, "label": ":", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 59, "label": ";" }
|
||||
]
|
||||
} }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,48 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1393, "label": "ձ" },
|
||||
{ "$": "auto_text_key", "code": 1397, "label": "յ" },
|
||||
{ "$": "auto_text_key", "code": 1413, "label": "օ" },
|
||||
{ "$": "auto_text_key", "code": 1404, "label": "ռ" },
|
||||
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
|
||||
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
|
||||
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
|
||||
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
|
||||
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
|
||||
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1389, "label": "խ" },
|
||||
{ "$": "auto_text_key", "code": 1410, "label": "ւ" },
|
||||
{ "$": "auto_text_key", "code": 1383, "label": "է" },
|
||||
{ "$": "auto_text_key", "code": 1408, "label": "ր" },
|
||||
{ "$": "auto_text_key", "code": 1407, "label": "տ" },
|
||||
{ "$": "auto_text_key", "code": 1381, "label": "ե" },
|
||||
{ "$": "auto_text_key", "code": 1384, "label": "ը" },
|
||||
{ "$": "auto_text_key", "code": 1387, "label": "ի" },
|
||||
{ "$": "auto_text_key", "code": 1400, "label": "ո" },
|
||||
{ "$": "auto_text_key", "code": 1402, "label": "պ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1377, "label": "ա" },
|
||||
{ "$": "auto_text_key", "code": 1405, "label": "ս" },
|
||||
{ "$": "auto_text_key", "code": 1380, "label": "դ" },
|
||||
{ "$": "auto_text_key", "code": 1414, "label": "ֆ" },
|
||||
{ "$": "auto_text_key", "code": 1412, "label": "ք" },
|
||||
{ "$": "auto_text_key", "code": 1392, "label": "հ" },
|
||||
{ "$": "auto_text_key", "code": 1395, "label": "ճ" },
|
||||
{ "$": "auto_text_key", "code": 1391, "label": "կ" },
|
||||
{ "$": "auto_text_key", "code": 1388, "label": "լ" },
|
||||
{ "$": "auto_text_key", "code": 1385, "label": "թ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1382, "label": "զ" },
|
||||
{ "$": "auto_text_key", "code": 1409, "label": "ց" },
|
||||
{ "$": "auto_text_key", "code": 1379, "label": "գ" },
|
||||
{ "$": "auto_text_key", "code": 1406, "label": "վ" },
|
||||
{ "$": "auto_text_key", "code": 1378, "label": "բ" },
|
||||
{ "$": "auto_text_key", "code": 1398, "label": "ն" },
|
||||
{ "$": "auto_text_key", "code": 1396, "label": "մ" },
|
||||
{ "$": "auto_text_key", "code": 1399, "label": "շ" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 228, "label": "ä" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" }
|
||||
]
|
||||
]
|
||||
@@ -2,44 +2,85 @@
|
||||
[
|
||||
{ "code": 39, "label": "'", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1474, "label": "ש\u05c2" },
|
||||
{ "code": 1467, "label": "ס\u05bb" },
|
||||
{ "code": 1523, "label": "׳" },
|
||||
{ "code": 1524, "label": "״" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 96, "label": "`" }
|
||||
]
|
||||
} },
|
||||
{ "code": 45, "label": "-", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1470, "label": "־" },
|
||||
{ "code": 1473, "label": "ש\u05c1" },
|
||||
{ "code": 95, "label": "_" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1511, "label": "ק" },
|
||||
{ "code": 1511, "label": "ק", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1464, "label": "ס\u05b8" },
|
||||
{ "code": 1459, "label": "ס\u05b3" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1512, "label": "ר" },
|
||||
{ "code": 1488, "label": "א" },
|
||||
{ "code": 1496, "label": "ט" },
|
||||
{ "code": 1493, "label": "ו" },
|
||||
{ "code": 1493, "label": "ו", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1465, "label": "ס\u05b9" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1503, "label": "ן" },
|
||||
{ "code": 1501, "label": "ם" },
|
||||
{ "code": 1508, "label": "פ" }
|
||||
{ "code": 1508, "label": "פ", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1463, "label": "ס\u05b7" },
|
||||
{ "code": 1458, "label": "ס\u05b2" }
|
||||
]
|
||||
} }
|
||||
],
|
||||
[
|
||||
{ "code": 1513, "label": "ש" },
|
||||
{ "code": 1491, "label": "ד" },
|
||||
{ "code": 1513, "label": "ש", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1456, "label": "ס\u05b0" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1491, "label": "ד", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1468, "label": "ס\u05bc" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1490, "label": "ג" },
|
||||
{ "code": 1499, "label": "כ" },
|
||||
{ "code": 1506, "label": "ע" },
|
||||
{ "code": 1497, "label": "י" },
|
||||
{ "code": 1495, "label": "ח" },
|
||||
{ "code": 1495, "label": "ח", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1460, "label": "ס\u05b4" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1500, "label": "ל" },
|
||||
{ "code": 1498, "label": "ך" },
|
||||
{ "code": 1507, "label": "ף" }
|
||||
],
|
||||
[
|
||||
{ "code": 1494, "label": "ז" },
|
||||
{ "code": 1505, "label": "ס" },
|
||||
{ "code": 1505, "label": "ס", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1462, "label": "ס\u05b6" },
|
||||
{ "code": 1457, "label": "ס\u05b1" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1489, "label": "ב" },
|
||||
{ "code": 1492, "label": "ה" },
|
||||
{ "code": 1504, "label": "נ" },
|
||||
{ "code": 1502, "label": "מ" },
|
||||
{ "code": 1510, "label": "צ" },
|
||||
{ "code": 1510, "label": "צ", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1461, "label": "ס\u05b5" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1514, "label": "ת" },
|
||||
{ "code": 1509, "label": "ץ" }
|
||||
]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[
|
||||
[
|
||||
{ "code": 1589, "label": "ص" },
|
||||
{ "code": 1602, "label": "ق" },
|
||||
{ "code": 1601, "label": "ف" },
|
||||
{ "code": 1594, "label": "غ" },
|
||||
{ "code": 1593, "label": "ع" },
|
||||
{ "code": 1607, "label": "ه" },
|
||||
{ "code": 1582, "label": "خ" },
|
||||
{ "code": 1581, "label": "ح" },
|
||||
{ "code": 1580, "label": "ج" },
|
||||
{ "code": 1670, "label": "چ" }
|
||||
],
|
||||
[
|
||||
{ "code": 1588, "label": "ش" },
|
||||
{ "code": 1587, "label": "س" },
|
||||
{ "code": 1740, "label": "ی" },
|
||||
{ "code": 1576, "label": "ب" },
|
||||
{ "code": 1604, "label": "ل" },
|
||||
{ "code": 1575, "label": "ا" },
|
||||
{ "code": 1578, "label": "ت" },
|
||||
{ "code": 1606, "label": "ن" },
|
||||
{ "code": 1605, "label": "م" },
|
||||
{ "code": 1705, "label": "ک" }
|
||||
],
|
||||
[
|
||||
{ "code": 8204, "label": "half_space" },
|
||||
{ "code": 1591, "label": "ط" },
|
||||
{ "code": 1586, "label": "ز" },
|
||||
{ "code": 1585, "label": "ر" },
|
||||
{ "code": 1584, "label": "ذ" },
|
||||
{ "code": 1583, "label": "د" },
|
||||
{ "code": 1608, "label": "و" },
|
||||
{ "code": 1711, "label": "گ" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
[
|
||||
[
|
||||
|
||||
{ "$": "auto_text_key", "code": 1393, "label": "ձ" },
|
||||
{ "$": "auto_text_key", "code": 1397, "label": "յ" },
|
||||
{ "$": "auto_text_key", "code": 1413, "label": "օ" },
|
||||
{ "$": "auto_text_key", "code": 1404, "label": "ռ" },
|
||||
{ "$": "auto_text_key", "code": 1386, "label": "ժ" },
|
||||
{ "$": "auto_text_key", "code": 1401, "label": "չ" },
|
||||
{ "$": "auto_text_key", "code": 1403, "label": "ջ" },
|
||||
{ "$": "auto_text_key", "code": 1411, "label": "փ" },
|
||||
{ "$": "auto_text_key", "code": 1394, "label": "ղ" },
|
||||
{ "$": "auto_text_key", "code": 1390, "label": "ծ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1389, "label": "խ" },
|
||||
{ "$": "auto_text_key", "code": 1406, "label": "վ" },
|
||||
{ "$": "auto_text_key", "code": 1383, "label": "է" },
|
||||
{ "$": "auto_text_key", "code": 1408, "label": "ր" },
|
||||
{ "$": "auto_text_key", "code": 1380, "label": "դ" },
|
||||
{ "$": "auto_text_key", "code": 1381, "label": "ե" },
|
||||
{ "$": "auto_text_key", "code": 1384, "label": "ը" },
|
||||
{ "$": "auto_text_key", "code": 1387, "label": "ի" },
|
||||
{ "$": "auto_text_key", "code": 1400, "label": "ո" },
|
||||
{ "$": "auto_text_key", "code": 1378, "label": "բ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1377, "label": "ա" },
|
||||
{ "$": "auto_text_key", "code": 1405, "label": "ս" },
|
||||
{ "$": "auto_text_key", "code": 1407, "label": "տ" },
|
||||
{ "$": "auto_text_key", "code": 1414, "label": "ֆ" },
|
||||
{ "$": "auto_text_key", "code": 1391, "label": "կ" },
|
||||
{ "$": "auto_text_key", "code": 1392, "label": "հ" },
|
||||
{ "$": "auto_text_key", "code": 1395, "label": "ճ" },
|
||||
{ "$": "auto_text_key", "code": 1412, "label": "ք" },
|
||||
{ "$": "auto_text_key", "code": 1388, "label": "լ" },
|
||||
{ "$": "auto_text_key", "code": 1385, "label": "թ" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1382, "label": "զ" },
|
||||
{ "$": "auto_text_key", "code": 1409, "label": "ց" },
|
||||
{ "$": "auto_text_key", "code": 1379, "label": "գ" },
|
||||
{ "$": "auto_text_key", "code": 1410, "label": "ւ" },
|
||||
{ "$": "auto_text_key", "code": 1402, "label": "պ" },
|
||||
{ "$": "auto_text_key", "code": 1398, "label": "ն" },
|
||||
{ "$": "auto_text_key", "code": 1396, "label": "մ" },
|
||||
{ "$": "auto_text_key", "code": 1399, "label": "շ" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
[
|
||||
[
|
||||
{ "code": -11, "label": "shift", "type": "modifier" },
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "$": "variation_selector",
|
||||
"default": { "code": 44, "label": ",", "groupId": 1 },
|
||||
"email": { "code": 64, "label": "@", "groupId": 1 },
|
||||
"uri": { "code": 47, "label": "/", "groupId": 1 }
|
||||
},
|
||||
{ "code": -227, "label": "language_switch", "type": "system_gui" },
|
||||
{ "code": -212, "label": "ime_ui_mode_media", "type": "system_gui" },
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 1417, "label": "։", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
[
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "code": -227, "label": "language_switch", "type": "system_gui" },
|
||||
{ "code": -212, "label": "ime_ui_mode_media", "type": "system_gui" },
|
||||
{ "$": "variation_selector",
|
||||
"default": { "code": 1548, "label": "،", "groupId": 1 },
|
||||
"email": { "code": 64, "label": "@", "groupId": 1 },
|
||||
"uri": { "code": 47, "label": "/", "groupId": 1 }
|
||||
},
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 46, "label": ".", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
[
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 35, "label": "#", "popup": {
|
||||
"main": { "code": 8470, "label": "№" }
|
||||
} },
|
||||
{ "code": -801, "label": "currency_slot_1", "popup": {
|
||||
"main": { "code": -802, "label": "currency_slot_2" },
|
||||
"relevant": [
|
||||
{ "code": -806, "label": "currency_slot_6" },
|
||||
{ "code": -803, "label": "currency_slot_3" },
|
||||
{ "code": -804, "label": "currency_slot_4" },
|
||||
{ "code": -805, "label": "currency_slot_5" }
|
||||
]
|
||||
} },
|
||||
{ "code": 37, "label": "%", "popup": {
|
||||
"main": { "code": 8240, "label": "‰" },
|
||||
"relevant": [
|
||||
{ "code": 8453, "label": "℅" }
|
||||
]
|
||||
} },
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 45, "label": "-", "popup": {
|
||||
"main": { "code": 95, "label": "_" },
|
||||
"relevant": [
|
||||
{ "code": 8212, "label": "—" },
|
||||
{ "code": 8211, "label": "–" },
|
||||
{ "code": 183, "label": "·" }
|
||||
]
|
||||
} },
|
||||
{ "code": 43, "label": "+", "popup": {
|
||||
"main": { "code": 177, "label": "±" }
|
||||
} },
|
||||
{ "code": 40, "label": "(", "popup": {
|
||||
"main": { "code": 60, "label": "<" },
|
||||
"relevant": [
|
||||
{ "code": 91, "label": "[" },
|
||||
{ "code": 123, "label": "{" }
|
||||
]
|
||||
} },
|
||||
{ "code": 41, "label": ")", "popup": {
|
||||
"main": { "code": 62, "label": ">" },
|
||||
"relevant": [
|
||||
{ "code": 93, "label": "]" },
|
||||
{ "code": 125, "label": "}" }
|
||||
]
|
||||
} },
|
||||
{ "code": 47, "label": "/" }
|
||||
],
|
||||
[
|
||||
{ "code": 42, "label": "*", "popup": {
|
||||
"main": { "code": 8224, "label": "†" },
|
||||
"relevant": [
|
||||
{ "code": 9733, "label": "★" },
|
||||
{ "code": 8225, "label": "‡" }
|
||||
]
|
||||
} },
|
||||
{ "code": 171, "label": "«", "popup": {
|
||||
"main": { "code": 34, "label": "\"" },
|
||||
"relevant": [
|
||||
{ "code": 8221, "label": "”" },
|
||||
{ "code": 8222, "label": "„" },
|
||||
{ "code": 8220, "label": "“" },
|
||||
{ "code": 8249, "label": "‹" }
|
||||
]
|
||||
} },
|
||||
{ "code": 187, "label": "»", "popup": {
|
||||
"main": { "code": 39, "label": "'" },
|
||||
"relevant": [
|
||||
{ "code": 8217, "label": "’" },
|
||||
{ "code": 8218, "label": "‚" },
|
||||
{ "code": 8216, "label": "‘" },
|
||||
{ "code": 8250, "label": "›" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1373, "label": "՝", "popup": {
|
||||
"main": { "code": 58, "label": ":" }
|
||||
} },
|
||||
{ "code": 46, "label": "." },
|
||||
{ "code": 1372, "label": "՜", "popup": {
|
||||
"main": { "code": 33, "label": "!" }
|
||||
} },
|
||||
{ "code": 1374, "label": "՞", "popup": {
|
||||
"main": { "code": 63, "label": "?" },
|
||||
"relevant": [
|
||||
{ "code": 191, "label": "¿" },
|
||||
{ "code": 8253, "label": "‽" }
|
||||
]
|
||||
} },
|
||||
{ "code": 1371, "label": "՛" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
[
|
||||
[
|
||||
{ "code": -203, "label": "view_symbols2", "type": "system_gui" },
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -201, "label": "view_characters", "type": "system_gui" },
|
||||
{ "code": 44, "label": "," },
|
||||
{ "code": -205, "label": "view_numeric_advanced", "type": "system_gui" },
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 1417, "label": "։", "popup": {
|
||||
"main": { "code": 46, "label": "." }
|
||||
} },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -70,6 +70,10 @@
|
||||
"id": "fa",
|
||||
"authors": [ "PHELAT" ]
|
||||
},
|
||||
{
|
||||
"id": "fa2",
|
||||
"authors": [ "M-Koushan" ]
|
||||
},
|
||||
{
|
||||
"id": "fi",
|
||||
"authors": [ "patrickgold" ]
|
||||
@@ -90,6 +94,10 @@
|
||||
"id": "hu",
|
||||
"authors": [ "zoli111, gabik65" ]
|
||||
},
|
||||
{
|
||||
"id": "hy",
|
||||
"authors": [ "PJTSearch" ]
|
||||
},
|
||||
{
|
||||
"id": "is",
|
||||
"authors": [ "patrickgold" ]
|
||||
@@ -172,7 +180,11 @@
|
||||
},
|
||||
{
|
||||
"id": "uk",
|
||||
"authors": [ "williamtheaker", "33kk" ]
|
||||
"authors": [ "williamtheaker", "33kk", "honsiorovskyi" ]
|
||||
},
|
||||
{
|
||||
"id": "uk-cyr-ext",
|
||||
"authors": [ "williamtheaker", "33kk", "honsiorovskyi" ]
|
||||
},
|
||||
{
|
||||
"id": "ur-PK",
|
||||
@@ -423,6 +435,18 @@
|
||||
"numericRow": "org.florisboard.layouts:persian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "fa-FA",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:rial",
|
||||
"popupMapping": "org.florisboard.localization:fa2",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:persian2",
|
||||
"symbols": "org.florisboard.layouts:persian",
|
||||
"symbols2": "org.florisboard.layouts:persian",
|
||||
"numericRow": "org.florisboard.layouts:persian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ar",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -435,6 +459,15 @@
|
||||
"numericRow": "org.florisboard.layouts:eastern_arabic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "az",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:azerbaijani_manat",
|
||||
"popupMapping": "org.florisboard.localization:tr",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:azerbaijani"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "hu",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -462,6 +495,26 @@
|
||||
"characters": "org.florisboard.layouts:qwertz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "hy",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:armenian_dram",
|
||||
"popupMapping": "org.florisboard.localization:hy",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:western_armenian",
|
||||
"symbols": "org.florisboard.layouts:armenian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "hy",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:armenian_dram",
|
||||
"popupMapping": "org.florisboard.localization:hy",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:eastern_armenian",
|
||||
"symbols": "org.florisboard.layouts:armenian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ru",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"main": { "code": -255, "label": ".sa"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
]
|
||||
},
|
||||
"ا": {
|
||||
"main": { "code": 1570, "label": "آ"},
|
||||
"relevant": [
|
||||
{ "code": 1649, "label": "ٱ" },
|
||||
{ "code": 1569, "label": "ء" },
|
||||
{ "code": 1571, "label": "أ" },
|
||||
{ "code": 1573, "label": "إ" },
|
||||
{ "code": 1570, "label": "آ" }
|
||||
{ "code": 1573, "label": "إ" }
|
||||
]
|
||||
},
|
||||
"ه": {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"all": {
|
||||
"ص": {
|
||||
"relevant": [
|
||||
{ "code": 1590, "label": "ض" }
|
||||
]
|
||||
},
|
||||
"half_space": {
|
||||
"relevant": [
|
||||
{ "code": 1622, "label": "ٖ" },
|
||||
{ "code": 1648, "label": "ٰ" },
|
||||
{ "code": 1619, "label": "ٓ" },
|
||||
{ "code": 1615, "label": "ُ" },
|
||||
{ "code": 1616, "label": "ِ" },
|
||||
{ "code": 1614, "label": "َ" },
|
||||
{ "code": 1600, "label": "ـ" },
|
||||
{ "code": 1621, "label": "ٕ" },
|
||||
{ "code": 1618, "label": "ْ" },
|
||||
{ "code": 1617, "label": "ّ" },
|
||||
{ "code": 1612, "label": "ٌ" },
|
||||
{ "code": 1613, "label": "ٍ" },
|
||||
{ "code": 1620, "label": "ٔ" }
|
||||
]
|
||||
},
|
||||
"ی": {
|
||||
"relevant": [
|
||||
{ "code": 1574, "label": "ئ" },
|
||||
{ "code": 1610, "label": "ي" },
|
||||
{ "code": 1746, "label": "ے" }
|
||||
]
|
||||
},
|
||||
"ا": {
|
||||
"main": { "code": 1570, "label": "آ"},
|
||||
"relevant": [
|
||||
{ "code": 1649, "label": "ٱ" },
|
||||
{ "code": 1569, "label": "ء" },
|
||||
{ "code": 1571, "label": "أ" },
|
||||
{ "code": 1573, "label": "إ" }
|
||||
]
|
||||
},
|
||||
"ه": {
|
||||
"relevant": [
|
||||
{ "code": 1729, "label": "ہ" },
|
||||
{ "code": 1728, "label": "ۀ" },
|
||||
{ "code": 1726, "label": "ھ" }
|
||||
]
|
||||
},
|
||||
"ت": {
|
||||
"relevant": [
|
||||
{ "code": 1579, "label": "ث" }
|
||||
]
|
||||
},
|
||||
"ک": {
|
||||
"relevant": [
|
||||
{ "code": 1706, "label": "ڪ"}
|
||||
]
|
||||
},
|
||||
"ط": {
|
||||
"relevant": [
|
||||
{ "code": 1592, "label": "ظ" }
|
||||
]
|
||||
},
|
||||
"ز": {
|
||||
"relevant": [
|
||||
{ "code": 1688, "label": "ژ" }
|
||||
]
|
||||
},
|
||||
"و": {
|
||||
"relevant": [
|
||||
{ "code": 1572, "label": "ؤ" }
|
||||
]
|
||||
},
|
||||
"گ": {
|
||||
"relevant": [
|
||||
{ "code": 1662, "label": "پ" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 1567, "label": "؟"},
|
||||
"relevant": [
|
||||
{ "code": 1563, "label": "؛" },
|
||||
{ "code": 58, "label": ":"},
|
||||
{ "code": 33, "label": "!" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".com" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"all": {
|
||||
"ե": {
|
||||
"main": { "$": "auto_text_key", "code": 1415, "label": "և" }
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 171, "label": "«" },
|
||||
{ "code": 187, "label": "»" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 1373, "label": "՝" },
|
||||
{ "code": 1371, "label": "՛" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 46, "label": "." },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "code": 40, "label": "(" },
|
||||
{ "code": 41, "label": ")" },
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 1372, "label": "՜" },
|
||||
{ "code": 1374, "label": "՞" },
|
||||
{ "code": 1415, "label": "և" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".gr" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"all": {
|
||||
"е": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1105, "label": "ё" }
|
||||
]
|
||||
},
|
||||
"у": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1118, "label": "ў" }
|
||||
]
|
||||
},
|
||||
"г": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1169, "label": "ґ" }
|
||||
]
|
||||
},
|
||||
"і": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1111, "label": "ї" },
|
||||
{ "$": "auto_text_key", "code": 1099, "label": "ы" }
|
||||
]
|
||||
},
|
||||
"є": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 8212, "label": "—" },
|
||||
{ "$": "auto_text_key", "code": 1101, "label": "э" }
|
||||
]
|
||||
},
|
||||
"ь": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 700, "label": "ʼ" },
|
||||
{ "$": "auto_text_key", "code": 39, "label": "'" },
|
||||
{ "$": "auto_text_key", "code": 1098, "label": "ъ" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".ua" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,26 @@
|
||||
{
|
||||
"all": {
|
||||
"г": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1169, "label": "ґ" }
|
||||
]
|
||||
},
|
||||
"і": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1111, "label": "ї" }
|
||||
]
|
||||
},
|
||||
"є": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 8212, "label": "—" }
|
||||
]
|
||||
},
|
||||
"ь": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 700, "label": "ʼ" },
|
||||
{ "$": "auto_text_key", "code": 39, "label": "'" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
@@ -37,7 +53,6 @@
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".ua" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".ir"},
|
||||
"main": { "code": -255, "label": ".pk"},
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_black",
|
||||
"label": "Floris Black",
|
||||
"authors": [ "serebit" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#388E3C",
|
||||
"colorPrimaryDark": "#306D32",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#EEEEEE"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#000000"
|
||||
},
|
||||
"key": {
|
||||
"background": "#212121",
|
||||
"backgroundPressed": "#3D3D3D",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "true"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#000000",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#424242",
|
||||
"backgroundActive": "#707070",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#7800BF",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "@key/background",
|
||||
"foreground": "@key/foreground"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#20388E3C"}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_black_borderless",
|
||||
"label": "Floris Black Borderless",
|
||||
"authors": [ "serebit" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#388E3C",
|
||||
"colorPrimaryDark": "#306D32",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#EEEEEE"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#000000"
|
||||
},
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"backgroundPressed": "#7F616161",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "false"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"key:space": {
|
||||
"background": "#46616161"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#000000",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#363636",
|
||||
"backgroundActive": "#5F5F5F",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#7800BF",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "#212121",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#20388E3C"}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_day",
|
||||
"label": "Floris Day",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": false,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "true",
|
||||
"semiTransparentColor": "#20000000",
|
||||
"textColor": "#000000"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#E0E0E0"
|
||||
},
|
||||
"key": {
|
||||
"background": "#FFFFFF",
|
||||
"backgroundPressed": "#F5F5F5",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "true"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#757575"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#E8F5E9",
|
||||
"foreground": "#424242"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#EEEEEE",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "@key/background",
|
||||
"foreground": "@key/foreground"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#E8E8E8",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_day_borderless",
|
||||
"label": "Floris Day Borderless",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": false,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "true",
|
||||
"semiTransparentColor": "#20000000",
|
||||
"textColor": "#000000"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#E0E0E0"
|
||||
},
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"backgroundPressed": "#7FF5F5F5",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "false"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"key:space": {
|
||||
"background": "#7FF5F5F5",
|
||||
"backgroundPressed": "#FFF5F5F5"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#757575"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#E8F5E9",
|
||||
"foreground": "#424242"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#EEEEEE",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "#FFFFFF",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#E8E8E8",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#8A8A8A"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_night",
|
||||
"label": "Floris Night",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#FFFFFF"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#212121"
|
||||
},
|
||||
"key": {
|
||||
"background": "#424242",
|
||||
"backgroundPressed": "#616161",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "true"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#1B5E20",
|
||||
"foreground": "#EEEEEE"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#757575",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "@key/background",
|
||||
"foreground": "@key/foreground"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
{
|
||||
"$type": "dev.patrickgold.florisboard.ime.theme.Theme",
|
||||
"name": "floris_night_borderless",
|
||||
"label": "Floris Night Borderless",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/background",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#FFFFFF"
|
||||
},
|
||||
"keyboard": {
|
||||
"background": "#212121"
|
||||
},
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"backgroundPressed": "#7F616161",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundPressed": "@window/textColor",
|
||||
"showBorder": "false"
|
||||
},
|
||||
"key:enter": {
|
||||
"background": "@window/colorPrimary",
|
||||
"backgroundPressed": "@window/colorPrimaryDark",
|
||||
"foreground": "#FFFFFF",
|
||||
"foregroundPressed": "#FFFFFF"
|
||||
},
|
||||
"key:shift:capslock": {
|
||||
"foreground": "@window/colorAccent",
|
||||
"foregroundPressed": "@window/colorAccent"
|
||||
},
|
||||
"key:space": {
|
||||
"background": "#2F616161",
|
||||
"backgroundPressed": "#7F616161"
|
||||
},
|
||||
"media": {
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"background": "#1B5E20",
|
||||
"foreground": "#EEEEEE"
|
||||
},
|
||||
"popup": {
|
||||
"background": "#757575",
|
||||
"backgroundActive": "#BDBDBD",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"privateMode": {
|
||||
"background": "#A000FF",
|
||||
"foreground": "#FFFFFF"
|
||||
},
|
||||
"smartbar": {
|
||||
"background": "transparent",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"background": "#424242",
|
||||
"foreground": "@window/textColor"
|
||||
},
|
||||
"extractEditLayout": {
|
||||
"background": "#282828",
|
||||
"foreground": "@window/textColor",
|
||||
"foregroundAlt": "#73FFFFFF"
|
||||
},
|
||||
"extractActionButton": {
|
||||
"background": "@smartbarButton/background",
|
||||
"foreground": "@smartbarButton/foreground"
|
||||
},
|
||||
"glideTrail": {"foreground": "#204CAF50"}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,14 @@
|
||||
"isBorderless": false,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_day_borderless",
|
||||
"label": "Floris Day (Borderless)",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNight": false,
|
||||
"isBorderless": true,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_night",
|
||||
"label": "Floris Night",
|
||||
@@ -24,6 +32,30 @@
|
||||
"isNight": true,
|
||||
"isBorderless": false,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_night_borderless",
|
||||
"label": "Floris Night (Borderless)",
|
||||
"authors": [ "patrickgold" ],
|
||||
"isNight": true,
|
||||
"isBorderless": true,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_pure_night",
|
||||
"label": "Floris Pure Night",
|
||||
"authors": [ "serebit" ],
|
||||
"isNight": true,
|
||||
"isBorderless": false,
|
||||
"isMaterialYouAware": false
|
||||
},
|
||||
{
|
||||
"id": "floris_pure_night_borderless",
|
||||
"label": "Floris Pure Night (Borderless)",
|
||||
"authors": [ "serebit" ],
|
||||
"isNight": true,
|
||||
"isBorderless": true,
|
||||
"isMaterialYouAware": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface-variant)",
|
||||
@@ -56,8 +56,8 @@
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
@@ -67,8 +67,8 @@
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "circle()"
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
@@ -127,15 +127,15 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
@@ -152,8 +152,8 @@
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
@@ -162,6 +162,23 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
"--secondary": "#ff9800",
|
||||
"--secondary-variant": "#e65100",
|
||||
"--background": "#e0e0e0",
|
||||
"--surface": "#f0f0f0",
|
||||
"--surface-variant": "#ffffff",
|
||||
|
||||
"--on-background": "#121212",
|
||||
"--on-surface": "#000000",
|
||||
"--on-surface-variant": "#5f5f5f",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][mode={m:capslock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#eeeeee",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#e8f5e9",
|
||||
"foreground": "#424242"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,8 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface-variant)",
|
||||
@@ -56,8 +56,8 @@
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
@@ -67,8 +67,8 @@
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "circle()"
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
@@ -127,15 +127,15 @@
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape-variant)"
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
@@ -152,8 +152,8 @@
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shadow-elevation": "2dp",
|
||||
"shape": "var(--shape)"
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
@@ -162,6 +162,23 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#4caf50",
|
||||
"--primary-variant": "#388e3c",
|
||||
"--secondary": "#f57c00",
|
||||
"--secondary-variant": "#e65100",
|
||||
"--background": "#212121",
|
||||
"--surface": "#424242",
|
||||
"--surface-variant": "#616161",
|
||||
|
||||
"--on-background": "#dcdcdc",
|
||||
"--on-surface": "#ffffff",
|
||||
"--on-surface-variant": "#a0a0a0",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][mode={m:capslock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#bdbdbd",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary)",
|
||||
"border-width": "2dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#1b5e20",
|
||||
"foreground": "#eeeeee"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#388e3c",
|
||||
"--primary-variant": "#306d32",
|
||||
"--secondary": "#ff9800",
|
||||
"--secondary-variant": "#804c00",
|
||||
"--background": "#000000",
|
||||
"--surface": "#212121",
|
||||
"--surface-variant": "#3d3d3d",
|
||||
|
||||
"--on-background": "#eeeeee",
|
||||
"--on-surface": "#eeeeee",
|
||||
"--on-surface-variant": "#ffffff73",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][mode={m:capslock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#424242",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#707070",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary-variant)",
|
||||
"border-width": "1dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary-variant)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#000000",
|
||||
"foreground": "#eeeeee"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
{
|
||||
"@defines": {
|
||||
"--primary": "#388e3c",
|
||||
"--primary-variant": "#306d32",
|
||||
"--secondary": "#ff9800",
|
||||
"--secondary-variant": "#804c00",
|
||||
"--background": "#000000",
|
||||
"--surface": "#212121",
|
||||
"--surface-variant": "#3d3d3d",
|
||||
|
||||
"--on-background": "#eeeeee",
|
||||
"--on-surface": "#eeeeee",
|
||||
"--on-surface-variant": "#ffffff73",
|
||||
|
||||
"--shape": "rounded-corner(8dp, 8dp, 8dp, 8dp)",
|
||||
"--shape-variant": "rounded-corner(12dp, 12dp, 12dp, 12dp)"
|
||||
},
|
||||
|
||||
"keyboard": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
|
||||
"key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"key:pressed": {
|
||||
"background": "#6161617f",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]": {
|
||||
"background": "var(--primary)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:enter}]:pressed": {
|
||||
"background": "var(--primary-variant)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"key[code={c:shift}][mode={m:capslock}]": {
|
||||
"foreground": "var(--secondary)"
|
||||
},
|
||||
"key[code={c:space}]": {
|
||||
"background": "#61616146",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-hint": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"font-size": "12sp"
|
||||
},
|
||||
"key-popup": {
|
||||
"background": "#363636",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"key-popup:focus": {
|
||||
"background": "#5F5F5F",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rectangle()"
|
||||
},
|
||||
"smartbar-candidate-word:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-clip": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "14sp",
|
||||
"shape": "rounded-corner(8%, 8%, 8%, 8%)"
|
||||
},
|
||||
"smartbar-candidate-clip:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"smartbar-candidate-spacer": {
|
||||
"foreground": "var(--surface)"
|
||||
},
|
||||
|
||||
"clipboard-header": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"clipboard-item": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"clipboard-item-popup": {
|
||||
"background": "var(--surface-variant)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "var(--shape-variant)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
|
||||
"emoji-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"emoji-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"emoji-key-popup": {
|
||||
"background": "#757575",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "22sp",
|
||||
"shape": "var(--shape)",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"emoji-tab": {
|
||||
"foreground": "var(--on-background)"
|
||||
},
|
||||
"emoji-tab:focus": {
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"extracted-landscape-input-layout": {
|
||||
"background": "var(--background)"
|
||||
},
|
||||
"extracted-landscape-input-field": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp",
|
||||
"shape": "rounded-corner(12dp, 12dp, 12dp, 12dp)",
|
||||
"border-color": "var(--secondary-variant)",
|
||||
"border-width": "1dp"
|
||||
},
|
||||
"extracted-landscape-input-action": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "rounded-corner(4dp, 4dp, 4dp, 4dp)"
|
||||
},
|
||||
|
||||
"glide-trail": {
|
||||
"foreground": "var(--primary-variant)"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#000000",
|
||||
"foreground": "#eeeeee"
|
||||
},
|
||||
|
||||
"system-nav-bar": {
|
||||
"background": "var(--background)"
|
||||
}
|
||||
}
|
||||
@@ -19,27 +19,33 @@ package dev.patrickgold.florisboard
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.inputmethodservice.ExtractEditText
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Size
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.ExtractedText
|
||||
import android.view.inputmethod.InlineSuggestionsRequest
|
||||
import android.view.inputmethod.InlineSuggestionsResponse
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.inline.InlinePresentationSpec
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.SideEffect
|
||||
@@ -49,22 +55,27 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.input.pointer.pointerInteropFilter
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.AbstractComposeView
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.WindowCompat
|
||||
import dev.patrickgold.florisboard.app.FlorisAppActivity
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.res.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.SystemUiIme
|
||||
import dev.patrickgold.florisboard.app.ui.devtools.DevtoolsOverlay
|
||||
import dev.patrickgold.florisboard.common.ViewUtils
|
||||
import dev.patrickgold.florisboard.common.android.AndroidInternalR
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationLandscape
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationPortrait
|
||||
@@ -83,6 +94,7 @@ import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.keyboard.InputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LocalInputFeedbackController
|
||||
import dev.patrickgold.florisboard.ime.keyboard.ProvideKeyboardRowBaseHeight
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
import dev.patrickgold.florisboard.ime.lifecycle.LifecycleInputMethodService
|
||||
import dev.patrickgold.florisboard.ime.media.MediaInputLayout
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
@@ -92,6 +104,12 @@ import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.snygg.ui.SnyggSurface
|
||||
import dev.patrickgold.florisboard.snygg.ui.shape
|
||||
import dev.patrickgold.florisboard.snygg.ui.snyggBackground
|
||||
import dev.patrickgold.florisboard.snygg.ui.snyggBorder
|
||||
import dev.patrickgold.florisboard.snygg.ui.snyggShadow
|
||||
import dev.patrickgold.florisboard.snygg.ui.solidColor
|
||||
import dev.patrickgold.florisboard.snygg.ui.spSize
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@@ -107,10 +125,6 @@ private var FlorisImeServiceReference = WeakReference<FlorisImeService?>(null)
|
||||
/**
|
||||
* Core class responsible for linking together all managers and UI compose-ables to provide an IME service. Sets
|
||||
* up the window and context to be lifecycle-aware, so LiveData and Jetpack Compose can be used without issues.
|
||||
*
|
||||
* This is a new implementation for the keyboard service class and is replacing the old core class bit by bit.
|
||||
* The main objective for the new class is to hold as few state as possible and delegate tasks to context-bound
|
||||
* manager classes.
|
||||
*/
|
||||
class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHistoryChangedListener {
|
||||
companion object {
|
||||
@@ -212,8 +226,14 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
private var inputViewSize by mutableStateOf(IntSize.Zero)
|
||||
private val inputFeedbackController by lazy { InputFeedbackController.new(this) }
|
||||
private var isWindowShown: Boolean = false
|
||||
private var isFullscreenUiMode by mutableStateOf(false)
|
||||
private var isExtractUiShown by mutableStateOf(false)
|
||||
private var resourcesContext by mutableStateOf(this as Context)
|
||||
|
||||
init {
|
||||
setTheme(R.style.FlorisImeTheme)
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
FlorisImeServiceReference = WeakReference(this)
|
||||
@@ -226,7 +246,7 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
}
|
||||
|
||||
override fun onCreateInputView(): View {
|
||||
super.onCreateInputView()
|
||||
super.installViewTreeOwners()
|
||||
val composeView = ComposeInputView()
|
||||
inputWindowView = composeView
|
||||
return composeView
|
||||
@@ -237,6 +257,24 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onCreateExtractTextView(): View {
|
||||
super.installViewTreeOwners()
|
||||
// Consider adding a fallback to the default extract edit layout if user reports come
|
||||
// that this causes a crash, especially if the device manufacturer of the user device
|
||||
// is a known one to break AOSP standards...
|
||||
val defaultExtractView = super.onCreateExtractTextView()
|
||||
if (defaultExtractView == null || defaultExtractView !is ViewGroup) {
|
||||
return ComposeExtractedLandscapeInputView(null)
|
||||
}
|
||||
val extractEditText = defaultExtractView.findViewById<ExtractEditText>(android.R.id.inputExtractEditText)
|
||||
(extractEditText?.parent as? ViewGroup)?.removeView(extractEditText)
|
||||
defaultExtractView.apply {
|
||||
removeAllViews()
|
||||
addView(ComposeExtractedLandscapeInputView(extractEditText))
|
||||
}
|
||||
return defaultExtractView
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
FlorisImeServiceReference = WeakReference(null)
|
||||
@@ -341,8 +379,17 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
isWindowShown = false
|
||||
}
|
||||
|
||||
override fun onEvaluateFullscreenMode(): Boolean {
|
||||
return when (prefs.keyboard.landscapeInputUiMode.get()) {
|
||||
LandscapeInputUiMode.DYNAMICALLY_SHOW -> super.onEvaluateFullscreenMode()
|
||||
LandscapeInputUiMode.NEVER_SHOW -> false
|
||||
LandscapeInputUiMode.ALWAYS_SHOW -> true
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateFullscreenMode() {
|
||||
super.updateFullscreenMode()
|
||||
isFullscreenUiMode = isFullscreenMode
|
||||
updateSoftInputWindowLayoutParameters()
|
||||
}
|
||||
|
||||
@@ -351,6 +398,23 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
activeEditorInstance.updateText(token, text)
|
||||
}
|
||||
|
||||
override fun onUpdateExtractingVisibility(ei: EditorInfo?) {
|
||||
if (ei != null) {
|
||||
activeState.update(ei)
|
||||
activeEditorInstance.editorInfo = ei
|
||||
}
|
||||
when (prefs.keyboard.landscapeInputUiMode.get()) {
|
||||
LandscapeInputUiMode.DYNAMICALLY_SHOW -> super.onUpdateExtractingVisibility(ei)
|
||||
LandscapeInputUiMode.NEVER_SHOW -> isExtractViewShown = false
|
||||
LandscapeInputUiMode.ALWAYS_SHOW -> isExtractViewShown = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun setExtractViewShown(shown: Boolean) {
|
||||
super.setExtractViewShown(shown)
|
||||
isExtractUiShown = shown
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
override fun onCreateInlineSuggestionsRequest(uiExtras: Bundle): InlineSuggestionsRequest? {
|
||||
return if (prefs.smartbar.enabled.get() && prefs.suggestion.api30InlineSuggestionsEnabled.get()) {
|
||||
@@ -420,7 +484,7 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
val w = window?.window ?: return
|
||||
WindowCompat.setDecorFitsSystemWindows(w, true)
|
||||
ViewUtils.updateLayoutHeightOf(w, WindowManager.LayoutParams.MATCH_PARENT)
|
||||
val layoutHeight = if (isFullscreenMode) {
|
||||
val layoutHeight = if (isFullscreenUiMode) {
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
} else {
|
||||
WindowManager.LayoutParams.MATCH_PARENT
|
||||
@@ -432,15 +496,39 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
ViewUtils.updateLayoutHeightOf(inputWindowView, layoutHeight)
|
||||
}
|
||||
|
||||
override fun getTextForImeAction(imeOptions: Int): String? {
|
||||
return try {
|
||||
when (imeOptions and EditorInfo.IME_MASK_ACTION) {
|
||||
EditorInfo.IME_ACTION_NONE -> null
|
||||
EditorInfo.IME_ACTION_GO -> resourcesContext.getString(AndroidInternalR.string.ime_action_go)
|
||||
EditorInfo.IME_ACTION_SEARCH -> resourcesContext.getString(AndroidInternalR.string.ime_action_search)
|
||||
EditorInfo.IME_ACTION_SEND -> resourcesContext.getString(AndroidInternalR.string.ime_action_send)
|
||||
EditorInfo.IME_ACTION_NEXT -> resourcesContext.getString(AndroidInternalR.string.ime_action_next)
|
||||
EditorInfo.IME_ACTION_DONE -> resourcesContext.getString(AndroidInternalR.string.ime_action_done)
|
||||
EditorInfo.IME_ACTION_PREVIOUS -> resourcesContext.getString(AndroidInternalR.string.ime_action_previous)
|
||||
else -> resourcesContext.getString(AndroidInternalR.string.ime_action_default)
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
super.getTextForImeAction(imeOptions)?.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ImeUiWrapper() {
|
||||
ProvideLocalizedResources(resourcesContext) {
|
||||
ProvideKeyboardRowBaseHeight {
|
||||
CompositionLocalProvider(LocalInputFeedbackController provides inputFeedbackController) {
|
||||
FlorisImeTheme {
|
||||
// Outer box is necessary as an "outer window"
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
DevtoolsUi()
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
if (!(isFullscreenUiMode && isExtractUiShown)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
) {
|
||||
DevtoolsUi()
|
||||
}
|
||||
}
|
||||
ImeUi()
|
||||
}
|
||||
SystemUiIme()
|
||||
@@ -452,7 +540,7 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
private fun BoxScope.ImeUi() {
|
||||
private fun ImeUi() {
|
||||
val activeState by keyboardManager.observeActiveState()
|
||||
val keyboardStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.Keyboard,
|
||||
@@ -467,7 +555,6 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.align(Alignment.BottomStart)
|
||||
.onGloballyPositioned { coords -> inputViewSize = coords.size }
|
||||
// Do not remove below line or touch input may get stuck
|
||||
.pointerInteropFilter { false },
|
||||
@@ -521,23 +608,13 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoxScope.DevtoolsUi() = with(LocalDensity.current) {
|
||||
private fun DevtoolsUi() {
|
||||
val devtoolsEnabled by prefs.devtools.enabled.observeAsState()
|
||||
if (devtoolsEnabled) {
|
||||
val maxHeight = inputWindowView?.measuredHeight?.let { windowHeight ->
|
||||
windowHeight - inputViewSize.height - FlorisImeSizing.Static.smartbarHeightPx
|
||||
} ?: inputViewSize.height
|
||||
DevtoolsOverlay(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.heightIn(max = maxHeight.toDp())
|
||||
.align(Alignment.TopStart),
|
||||
)
|
||||
DevtoolsOverlay(modifier = Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,4 +638,111 @@ class FlorisImeService : LifecycleInputMethodService(), EditorInstance.WordHisto
|
||||
updateSoftInputWindowLayoutParameters()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ComposeExtractedLandscapeInputView(eet: ExtractEditText?) : FrameLayout(this) {
|
||||
val composeView: ComposeView
|
||||
val extractEditText: ExtractEditText
|
||||
|
||||
init {
|
||||
isHapticFeedbackEnabled = true
|
||||
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
|
||||
extractEditText = (eet ?: ExtractEditText(context)).also {
|
||||
it.id = android.R.id.inputExtractEditText
|
||||
it.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
it.background = null
|
||||
it.gravity = Gravity.TOP
|
||||
it.isVerticalScrollBarEnabled = true
|
||||
}
|
||||
addView(extractEditText)
|
||||
|
||||
composeView = ComposeView(context).also { it.setContent { Content() } }
|
||||
addView(composeView)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Content() {
|
||||
ProvideLocalizedResources(resourcesContext, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
FlorisImeTheme {
|
||||
val layoutStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputLayout)
|
||||
val fieldStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputField)
|
||||
val actionStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputAction)
|
||||
val activeState by keyboardManager.observeActiveState()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.snyggBackground(layoutStyle, FlorisImeTheme.fallbackSurfaceColor()),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val fieldColor = fieldStyle.foreground.solidColor(FlorisImeTheme.fallbackContentColor())
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.snyggShadow(fieldStyle)
|
||||
.snyggBorder(fieldStyle)
|
||||
.snyggBackground(fieldStyle),
|
||||
factory = { extractEditText },
|
||||
update = { view ->
|
||||
view.background = null
|
||||
view.backgroundTintList = null
|
||||
view.foregroundTintList = null
|
||||
view.setTextColor(fieldColor.toArgb())
|
||||
view.setHintTextColor(fieldColor.copy(fieldColor.alpha * 0.6f).toArgb())
|
||||
view.setTextSize(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
fieldStyle.fontSize.spSize(default = 16.sp).value,
|
||||
)
|
||||
},
|
||||
)
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
val ei = activeEditorInstance.editorInfo
|
||||
if (ei != null) {
|
||||
if (ei.actionId != 0) {
|
||||
activeEditorInstance.inputConnection?.performEditorAction(ei.actionId)
|
||||
} else {
|
||||
activeEditorInstance.performEnterAction(activeState.imeOptions.enterAction)
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
text = activeEditorInstance.editorInfo?.actionLabel?.toString()
|
||||
?: getTextForImeAction(activeState.imeOptions.enterAction.toInt())
|
||||
?: "ACTION",
|
||||
shape = actionStyle.shape.shape(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = actionStyle.background.solidColor(FlorisImeTheme.fallbackContentColor()),
|
||||
contentColor = actionStyle.foreground.solidColor(FlorisImeTheme.fallbackSurfaceColor()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAccessibilityClassName(): CharSequence {
|
||||
return javaClass.name
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
removeView(extractEditText)
|
||||
super.onAttachedToWindow()
|
||||
try {
|
||||
(parent as LinearLayout).let { extractEditLayout ->
|
||||
extractEditLayout.layoutParams = LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
).also { it.setMargins(0, 0, 0, 0) }
|
||||
extractEditLayout.setPadding(0, 0, 0, 0)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
flogError { e.message.toString() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.prefs
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import dev.patrickgold.florisboard.app.AppTheme
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.DisplayColorsAs
|
||||
import dev.patrickgold.florisboard.app.ui.settings.theme.DisplayKbdAfterDialogs
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationPortrait
|
||||
import dev.patrickgold.florisboard.common.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
@@ -41,6 +46,7 @@ import dev.patrickgold.florisboard.snygg.SnyggLevel
|
||||
import dev.patrickgold.florisboard.util.VersionName
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceModel
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
|
||||
fun florisPreferenceModel() = JetPref.getOrCreatePreferenceModel(AppPrefs::class, ::AppPrefs)
|
||||
|
||||
@@ -438,6 +444,24 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
mergeHintPopups = mergeHintPopupsEnabled.get(),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun fontSizeMultiplier(): Float {
|
||||
val configuration = LocalConfiguration.current
|
||||
val oneHandedMode by oneHandedMode.observeAsState()
|
||||
val oneHandedModeFactor by oneHandedModeScaleFactor.observeAsTransformingState { it / 100.0f }
|
||||
val fontSizeMultiplierBase by if (configuration.isOrientationPortrait()) {
|
||||
fontSizeMultiplierPortrait
|
||||
} else {
|
||||
fontSizeMultiplierLandscape
|
||||
}.observeAsTransformingState { it / 100.0f }
|
||||
val fontSizeMultiplier = fontSizeMultiplierBase * if (oneHandedMode != OneHandedMode.OFF && configuration.isOrientationPortrait()) {
|
||||
oneHandedModeFactor
|
||||
} else {
|
||||
1.0f
|
||||
}
|
||||
return fontSizeMultiplier
|
||||
}
|
||||
}
|
||||
|
||||
val localization = Localization()
|
||||
|
||||
@@ -41,9 +41,10 @@ private val LocalAppNameString = staticCompositionLocalOf {
|
||||
@Composable
|
||||
fun ProvideLocalizedResources(
|
||||
resourcesContext: Context,
|
||||
forceLayoutDirection: LayoutDirection? = null,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val layoutDirection = when (resourcesContext.resources.configuration.layoutDirection) {
|
||||
val layoutDirection = forceLayoutDirection ?: when (resourcesContext.resources.configuration.layoutDirection) {
|
||||
View.LAYOUT_DIRECTION_LTR -> LayoutDirection.Ltr
|
||||
View.LAYOUT_DIRECTION_RTL -> LayoutDirection.Rtl
|
||||
else -> error("Given configuration specifies invalid layout direction!")
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.NonRestartableComposable
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
|
||||
@Composable
|
||||
@NonRestartableComposable
|
||||
fun DisposableLifecycleEffect(
|
||||
lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle,
|
||||
onResume: () -> Unit,
|
||||
onPause: () -> Unit,
|
||||
) {
|
||||
DisposableEffect(lifecycle) {
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_RESUME -> onResume()
|
||||
Lifecycle.Event.ON_PAUSE -> onPause()
|
||||
else -> { }
|
||||
}
|
||||
}
|
||||
lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
lifecycle.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.LocalContentAlpha
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
@@ -37,6 +38,7 @@ import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -48,12 +50,14 @@ fun FlorisButton(
|
||||
icon: Painter? = null,
|
||||
text: String,
|
||||
enabled: Boolean = true,
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||
) {
|
||||
Button(
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
contentPadding = contentPadding,
|
||||
onClick = onClick,
|
||||
@@ -78,12 +82,14 @@ fun FlorisOutlinedButton(
|
||||
icon: Painter? = null,
|
||||
text: String,
|
||||
enabled: Boolean = true,
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||
colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
|
||||
) {
|
||||
OutlinedButton(
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
contentPadding = contentPadding,
|
||||
onClick = onClick,
|
||||
@@ -108,12 +114,14 @@ fun FlorisTextButton(
|
||||
icon: Painter? = null,
|
||||
text: String,
|
||||
enabled: Boolean = true,
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
contentPadding: PaddingValues = ButtonDefaults.TextButtonContentPadding,
|
||||
colors: ButtonColors = ButtonDefaults.textButtonColors(),
|
||||
) {
|
||||
TextButton(
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
contentPadding = contentPadding,
|
||||
onClick = onClick,
|
||||
|
||||
@@ -62,7 +62,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.app.ui.theme.outline
|
||||
|
||||
private val StepHeaderPaddingVertical = 16.dp
|
||||
private val StepHeaderPaddingVertical = 8.dp
|
||||
private val StepHeaderNumberBoxSize = 40.dp
|
||||
private val StepHeaderNumberBoxPaddingEnd = 16.dp
|
||||
private val StepHeaderTextBoxHeight = 32.dp
|
||||
|
||||
@@ -23,12 +23,15 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisScreen
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
@@ -39,17 +42,22 @@ fun AndroidLocalesScreen() = FlorisScreen {
|
||||
val availableLocales = remember { Locale.getAvailableLocales().sortedBy { it.toLanguageTag() } }
|
||||
|
||||
content {
|
||||
val displayLanguageNamesIn by prefs.localization.displayLanguageNamesIn.observeAsState()
|
||||
|
||||
SelectionContainer(modifier = Modifier.fillMaxWidth()) {
|
||||
LazyColumn {
|
||||
items(availableLocales) {
|
||||
items(availableLocales) { locale ->
|
||||
Row {
|
||||
Text(
|
||||
text = it.toLanguageTag().padEnd(12),
|
||||
text = locale.toLanguageTag().padEnd(12),
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.weight(1.0f),
|
||||
text = it.getDisplayName(it),
|
||||
text = when (displayLanguageNamesIn) {
|
||||
DisplayLanguageNamesIn.SYSTEM_LOCALE -> locale.displayName
|
||||
DisplayLanguageNamesIn.NATIVE_LOCALE -> locale.getDisplayName(locale)
|
||||
},
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package dev.patrickgold.florisboard.app.ui.devtools
|
||||
import android.view.textservice.SuggestionsInfo
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.LocalContentColor
|
||||
@@ -50,12 +51,8 @@ private val CardBackground = Color.Black.copy(0.6f)
|
||||
private val DateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", FlorisLocale.default().base)
|
||||
|
||||
@Composable
|
||||
fun DevtoolsOverlay(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val context = LocalContext.current
|
||||
val clipboardManager by context.clipboardManager()
|
||||
|
||||
val showPrimaryClip by prefs.devtools.showPrimaryClip.observeAsState()
|
||||
val showSpellingOverlay by prefs.devtools.showSpellingOverlay.observeAsState()
|
||||
@@ -66,11 +63,7 @@ fun DevtoolsOverlay(
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
if (showPrimaryClip) {
|
||||
val primaryClip by clipboardManager.primaryClip.observeAsState()
|
||||
Text(
|
||||
text = primaryClip.toString(),
|
||||
color = Color.White,
|
||||
)
|
||||
DevtoolsClipboardOverlay()
|
||||
}
|
||||
if (showSpellingOverlay) {
|
||||
DevtoolsSpellingOverlay()
|
||||
@@ -79,6 +72,21 @@ fun DevtoolsOverlay(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsClipboardOverlay() {
|
||||
val context = LocalContext.current
|
||||
val clipboardManager by context.clipboardManager()
|
||||
|
||||
DevtoolsOverlayBox(title = "Clipboard overlay") {
|
||||
val primaryClip by clipboardManager.primaryClip.observeAsState()
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 8.dp, start = 8.dp, end = 8.dp),
|
||||
text = primaryClip.toString(),
|
||||
color = Color.White,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsSpellingOverlay() {
|
||||
val context = LocalContext.current
|
||||
@@ -87,18 +95,8 @@ private fun DevtoolsSpellingOverlay() {
|
||||
val debugOverlayVersion by spellingManager.debugOverlayVersion.observeAsNonNullState()
|
||||
val suggestionsInfos = remember(debugOverlayVersion) { spellingManager.debugOverlaySuggestionsInfos.snapshot() }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.background(CardBackground),
|
||||
) {
|
||||
val sortedEntries = suggestionsInfos.entries.sortedByDescending { it.key }
|
||||
Text(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
text = "Spelling overlay (${sortedEntries.size})",
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
val sortedEntries = suggestionsInfos.entries.sortedByDescending { it.key }
|
||||
DevtoolsOverlayBox(title = "Spelling overlay (${sortedEntries.size})") {
|
||||
for ((timestamp, wordInfoPair) in sortedEntries) {
|
||||
val (word, info) = wordInfoPair
|
||||
val isTypo = (info.suggestionsAttributes and SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0
|
||||
@@ -131,3 +129,23 @@ private fun DevtoolsSpellingOverlay() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsOverlayBox(
|
||||
title: String,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.fillMaxWidth()
|
||||
.background(CardBackground),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(all = 8.dp),
|
||||
text = title,
|
||||
fontSize = 14.sp,
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ fun AdvancedScreen() = FlorisScreen {
|
||||
"tr",
|
||||
"uk",
|
||||
"zgh",
|
||||
"zh-CN",
|
||||
).map { languageTag ->
|
||||
if (languageTag == "auto") {
|
||||
entry(
|
||||
|
||||
@@ -52,7 +52,6 @@ import dev.patrickgold.florisboard.app.ui.components.defaultFlorisOutlinedBox
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.common.android.readToFile
|
||||
import dev.patrickgold.florisboard.common.android.showLongToast
|
||||
import dev.patrickgold.florisboard.res.FileRegistry
|
||||
import dev.patrickgold.florisboard.res.ZipUtils
|
||||
import dev.patrickgold.florisboard.res.cache.CacheManager
|
||||
import dev.patrickgold.florisboard.res.ext.ExtensionManager
|
||||
@@ -65,6 +64,7 @@ import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.FileNotFoundException
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
@@ -84,6 +84,7 @@ fun RestoreScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.backup_and_restore__restore__title)
|
||||
previewFieldVisible = false
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
val cacheManager by context.cacheManager()
|
||||
@@ -108,7 +109,11 @@ fun RestoreScreen() = FlorisScreen {
|
||||
workspace.zipFile = workspace.inputDir.subFile(Restore.BACKUP_ARCHIVE_FILE_NAME)
|
||||
context.contentResolver.readToFile(uri, workspace.zipFile)
|
||||
ZipUtils.unzip(workspace.zipFile, workspace.outputDir)
|
||||
workspace.metadata = workspace.outputDir.subFile(Backup.METADATA_JSON_NAME).readJson()
|
||||
workspace.metadata = try {
|
||||
workspace.outputDir.subFile(Backup.METADATA_JSON_NAME).readJson()
|
||||
} catch (e: FileNotFoundException) {
|
||||
error("Invalid archive: either backup_metadata.json is missing or file is not a ZIP archive.")
|
||||
}
|
||||
workspace.restoreWarningId = when {
|
||||
workspace.metadata.versionCode != BuildConfig.VERSION_CODE -> {
|
||||
R.string.backup_and_restore__restore__metadata_warn_different_version
|
||||
@@ -132,7 +137,6 @@ fun RestoreScreen() = FlorisScreen {
|
||||
)
|
||||
|
||||
suspend fun performRestore() {
|
||||
val prefs by florisPreferenceModel()
|
||||
val workspace = restoreWorkspace!!
|
||||
val shouldReset = restoreMode == Restore.Mode.ERASE_AND_OVERWRITE
|
||||
if (restoreFilesSelector.jetprefDatastore) {
|
||||
@@ -228,9 +232,7 @@ fun RestoreScreen() = FlorisScreen {
|
||||
FlorisOutlinedButton(
|
||||
onClick = {
|
||||
runCatching {
|
||||
restoreDataFromFileSystemLauncher.launch(
|
||||
FileRegistry.BackupArchive.mediaType
|
||||
)
|
||||
restoreDataFromFileSystemLauncher.launch("*/*")
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(R.string.backup_and_restore__restore__failure, "error_message" to error.localizedMessage)
|
||||
}
|
||||
|
||||
@@ -16,26 +16,51 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.ui.settings.theme
|
||||
|
||||
import android.icu.lang.UCharacter
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateColor
|
||||
import androidx.compose.animation.core.RepeatMode
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
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.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.widthIn
|
||||
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
|
||||
import androidx.compose.foundation.text.selection.TextSelectionColors
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.res.stringRes
|
||||
@@ -45,15 +70,34 @@ import dev.patrickgold.florisboard.app.ui.components.FlorisHyperlinkText
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisIconButton
|
||||
import dev.patrickgold.florisboard.app.ui.components.FlorisOutlinedTextField
|
||||
import dev.patrickgold.florisboard.app.ui.components.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.common.InputMethodUtils
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.android.showShortToast
|
||||
import dev.patrickgold.florisboard.common.android.stringRes
|
||||
import dev.patrickgold.florisboard.common.kotlin.curlyFormat
|
||||
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
|
||||
import dev.patrickgold.florisboard.ime.core.InputKeyEventReceiver
|
||||
import dev.patrickgold.florisboard.ime.keyboard.ComputingEvaluator
|
||||
import dev.patrickgold.florisboard.ime.keyboard.DefaultComputingEvaluator
|
||||
import dev.patrickgold.florisboard.ime.keyboard.Key
|
||||
import dev.patrickgold.florisboard.ime.keyboard.Keyboard
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeIconResId
|
||||
import dev.patrickgold.florisboard.ime.keyboard.computeLabel
|
||||
import dev.patrickgold.florisboard.ime.nlp.NATIVE_NULLPTR
|
||||
import dev.patrickgold.florisboard.ime.text.key.InputMode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUiSpec
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.snygg.SnyggLevel
|
||||
import dev.patrickgold.florisboard.snygg.SnyggRule
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
|
||||
private val TransparentTextSelectionColors = TextSelectionColors(
|
||||
handleColor = Color.Transparent,
|
||||
backgroundColor = Color.Transparent,
|
||||
)
|
||||
internal val SnyggEmptyRuleForAdding = SnyggRule(element = "- select -")
|
||||
|
||||
@Composable
|
||||
@@ -194,13 +238,15 @@ internal fun EditRuleDialog(
|
||||
)
|
||||
},
|
||||
) {
|
||||
if (codes.isEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
text = stringRes(R.string.settings__theme_editor__no_codes_defined),
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
}
|
||||
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(
|
||||
@@ -247,102 +293,302 @@ internal fun EditRuleDialog(
|
||||
|
||||
val initCodeValue = editCodeDialogValue
|
||||
if (initCodeValue != null) {
|
||||
var inputCodeString by rememberSaveable(initCodeValue) { mutableStateOf(initCodeValue.toString()) }
|
||||
var showKeyCodesHelp by rememberSaveable(initCodeValue) { mutableStateOf(false) }
|
||||
var showError by rememberSaveable(initCodeValue) { mutableStateOf(false) }
|
||||
var errorId by rememberSaveable(initCodeValue) { mutableStateOf(NATIVE_NULLPTR) }
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(if (initCodeValue == NATIVE_NULLPTR) {
|
||||
R.string.settings__theme_editor__add_code
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_code
|
||||
}),
|
||||
confirmLabel = stringRes(if (initCodeValue == NATIVE_NULLPTR) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}),
|
||||
onConfirm = {
|
||||
val code = inputCodeString.trim().toIntOrNull(radix = 10)
|
||||
when {
|
||||
code == null || (code !in KeyCode.Spec.CHARACTERS && code !in KeyCode.Spec.INTERNAL) -> {
|
||||
errorId = R.string.settings__theme_editor__code_invalid
|
||||
showError = true
|
||||
}
|
||||
code == initCodeValue -> {
|
||||
editCodeDialogValue = null
|
||||
}
|
||||
codes.contains(code) -> {
|
||||
errorId = R.string.settings__theme_editor__code_already_exists
|
||||
showError = true
|
||||
}
|
||||
else -> {
|
||||
if (initCodeValue != NATIVE_NULLPTR) {
|
||||
codes.remove(initCodeValue)
|
||||
}
|
||||
codes.add(code)
|
||||
editCodeDialogValue = null
|
||||
}
|
||||
EditCodeValueDialog(
|
||||
codeValue = initCodeValue,
|
||||
checkExisting = { codes.contains(it) },
|
||||
onAdd = { codes.add(it) },
|
||||
onDelete = { codes.remove(it) },
|
||||
onDismiss = { editCodeDialogValue = null },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditCodeValueDialog(
|
||||
codeValue: Int,
|
||||
checkExisting: (Int) -> Boolean,
|
||||
onAdd: (Int) -> Unit,
|
||||
onDelete: (Int) -> 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()
|
||||
mutableStateOf(str)
|
||||
}
|
||||
val textKeyData = remember(inputCodeString) {
|
||||
inputCodeString.toIntOrNull()?.let { code ->
|
||||
TextKeyData.getCodeInfoAsTextKeyData(code)
|
||||
}
|
||||
}
|
||||
var showKeyCodesHelp by rememberSaveable(codeValue) { mutableStateOf(false) }
|
||||
var showError by rememberSaveable(codeValue) { mutableStateOf(false) }
|
||||
var errorId by rememberSaveable(codeValue) { mutableStateOf(NATIVE_NULLPTR) }
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val isFlorisBoardEnabled by InputMethodUtils.observeIsFlorisboardEnabled(foregroundOnly = true)
|
||||
val isFlorisBoardSelected by InputMethodUtils.observeIsFlorisboardSelected(foregroundOnly = true)
|
||||
|
||||
var isRecordingKey by remember { mutableStateOf(false) }
|
||||
var lastRecordingToast by remember { mutableStateOf<Toast?>(null) }
|
||||
val recordingKeyColor = if (isRecordingKey) {
|
||||
rememberInfiniteTransition().animateColor(
|
||||
initialValue = LocalContentColor.current,
|
||||
targetValue = MaterialTheme.colors.error,
|
||||
animationSpec = infiniteRepeatable(
|
||||
tween(750),
|
||||
repeatMode = RepeatMode.Reverse,
|
||||
),
|
||||
).value
|
||||
} else {
|
||||
LocalContentColor.current
|
||||
}
|
||||
|
||||
fun requestStartRecording() {
|
||||
if (isRecordingKey) {
|
||||
isRecordingKey = false
|
||||
return
|
||||
}
|
||||
if (!isFlorisBoardEnabled || !isFlorisBoardSelected) {
|
||||
lastRecordingToast?.cancel()
|
||||
lastRecordingToast = context.showShortToast(
|
||||
R.string.settings__theme_editor__code_recording_requires_default_ime_floris,
|
||||
"app_name" to context.stringRes(R.string.floris_app_name),
|
||||
)
|
||||
InputMethodUtils.showImePicker(context)
|
||||
return
|
||||
}
|
||||
showError = false
|
||||
isRecordingKey = true
|
||||
}
|
||||
|
||||
if (isRecordingKey) {
|
||||
DisposableEffect(Unit) {
|
||||
val receiver = object : InputKeyEventReceiver {
|
||||
override fun onInputKeyDown(ev: InputKeyEvent) = Unit
|
||||
override fun onInputKeyUp(ev: InputKeyEvent) {
|
||||
inputCodeString = ev.data.code.toString()
|
||||
isRecordingKey = false
|
||||
}
|
||||
},
|
||||
dismissLabel = stringRes(R.string.action__cancel),
|
||||
onDismiss = {
|
||||
editCodeDialogValue = null
|
||||
},
|
||||
neutralLabel = if (initCodeValue != NATIVE_NULLPTR) {
|
||||
stringRes(R.string.action__delete)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error),
|
||||
onNeutral = {
|
||||
codes.remove(initCodeValue)
|
||||
editCodeDialogValue = null
|
||||
},
|
||||
trailingIconTitle = {
|
||||
FlorisIconButton(
|
||||
onClick = { showKeyCodesHelp = !showKeyCodesHelp },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = painterResource(R.drawable.ic_help_outline),
|
||||
)
|
||||
},
|
||||
) {
|
||||
Column {
|
||||
AnimatedVisibility(visible = showKeyCodesHelp) {
|
||||
Column(modifier = Modifier.padding(bottom = 16.dp)) {
|
||||
Text(text = stringRes(R.string.settings__theme_editor__code_help_text))
|
||||
FlorisHyperlinkText(
|
||||
text = "Characters (unicode-table.com)",
|
||||
url = stringRes(R.string.florisboard__character_key_codes_url),
|
||||
)
|
||||
FlorisHyperlinkText(
|
||||
text = "Internal (github.com)",
|
||||
url = stringRes(R.string.florisboard__internal_key_codes_url),
|
||||
)
|
||||
}
|
||||
override fun onInputKeyRepeat(ev: InputKeyEvent) = Unit
|
||||
override fun onInputKeyCancel(ev: InputKeyEvent) = Unit
|
||||
}
|
||||
val defaultReceiver = keyboardManager.inputEventDispatcher.keyEventReceiver
|
||||
keyboardManager.inputEventDispatcher.keyEventReceiver = receiver
|
||||
lastRecordingToast?.cancel()
|
||||
lastRecordingToast = context.showShortToast(R.string.settings__theme_editor__code_recording_started)
|
||||
focusRequester.requestFocus()
|
||||
onDispose {
|
||||
keyboardManager.inputEventDispatcher.keyEventReceiver = defaultReceiver
|
||||
lastRecordingToast?.cancel()
|
||||
lastRecordingToast = context.showShortToast(R.string.settings__theme_editor__code_recording_stopped)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(if (codeValue == NATIVE_NULLPTR) {
|
||||
R.string.settings__theme_editor__add_code
|
||||
} else {
|
||||
R.string.settings__theme_editor__edit_code
|
||||
}),
|
||||
confirmLabel = stringRes(if (codeValue == NATIVE_NULLPTR) {
|
||||
R.string.action__add
|
||||
} else {
|
||||
R.string.action__apply
|
||||
}),
|
||||
onConfirm = {
|
||||
val code = inputCodeString.trim().toIntOrNull(radix = 10)
|
||||
when {
|
||||
code == null || (code !in KeyCode.Spec.CHARACTERS && code !in KeyCode.Spec.INTERNAL) -> {
|
||||
errorId = R.string.settings__theme_editor__code_invalid
|
||||
showError = true
|
||||
}
|
||||
FlorisOutlinedTextField(
|
||||
value = inputCodeString,
|
||||
onValueChange = { v ->
|
||||
inputCodeString = v
|
||||
showError = false
|
||||
},
|
||||
isError = showError,
|
||||
singleLine = true,
|
||||
)
|
||||
AnimatedVisibility(visible = showError) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
text = stringRes(errorId).curlyFormat(
|
||||
"c_min" to KeyCode.Spec.CHARACTERS_MIN,
|
||||
"c_max" to KeyCode.Spec.CHARACTERS_MAX,
|
||||
"i_min" to KeyCode.Spec.INTERNAL_MIN,
|
||||
"i_max" to KeyCode.Spec.INTERNAL_MAX,
|
||||
),
|
||||
color = MaterialTheme.colors.error,
|
||||
code == codeValue -> {
|
||||
onDismiss()
|
||||
}
|
||||
checkExisting(code) -> {
|
||||
errorId = R.string.settings__theme_editor__code_already_exists
|
||||
showError = true
|
||||
}
|
||||
else -> {
|
||||
if (codeValue != NATIVE_NULLPTR) {
|
||||
onDelete(codeValue)
|
||||
}
|
||||
onAdd(code)
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissLabel = stringRes(R.string.action__cancel),
|
||||
onDismiss = onDismiss,
|
||||
neutralLabel = if (codeValue != NATIVE_NULLPTR) {
|
||||
stringRes(R.string.action__delete)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
neutralColors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.error),
|
||||
onNeutral = {
|
||||
onDelete(codeValue)
|
||||
onDismiss()
|
||||
},
|
||||
trailingIconTitle = {
|
||||
FlorisIconButton(
|
||||
onClick = { showKeyCodesHelp = !showKeyCodesHelp },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = painterResource(R.drawable.ic_help_outline),
|
||||
)
|
||||
},
|
||||
) {
|
||||
Column {
|
||||
AnimatedVisibility(visible = showKeyCodesHelp) {
|
||||
Column(modifier = Modifier.padding(bottom = 16.dp)) {
|
||||
Text(text = stringRes(R.string.settings__theme_editor__code_recording_help_text))
|
||||
Text(text = stringRes(R.string.settings__theme_editor__code_help_text))
|
||||
FlorisHyperlinkText(
|
||||
text = "Characters (unicode-table.com)",
|
||||
url = stringRes(R.string.florisboard__character_key_codes_url),
|
||||
)
|
||||
FlorisHyperlinkText(
|
||||
text = "Internal (github.com)",
|
||||
url = stringRes(R.string.florisboard__internal_key_codes_url),
|
||||
)
|
||||
}
|
||||
}
|
||||
TextKeyDataPreviewBox(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
textKeyData = textKeyData,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val textSelectionColors = if (isRecordingKey) {
|
||||
TransparentTextSelectionColors
|
||||
} else {
|
||||
LocalTextSelectionColors.current
|
||||
}
|
||||
CompositionLocalProvider(LocalTextSelectionColors provides textSelectionColors) {
|
||||
FlorisOutlinedTextField(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.weight(1f),
|
||||
value = inputCodeString,
|
||||
onValueChange = { v ->
|
||||
inputCodeString = v
|
||||
showError = false
|
||||
},
|
||||
placeholder = when {
|
||||
isRecordingKey -> {
|
||||
stringRes(R.string.settings__theme_editor__code_recording_placeholder)
|
||||
}
|
||||
inputCodeString.isEmpty() -> {
|
||||
stringRes(R.string.settings__theme_editor__code_placeholder)
|
||||
}
|
||||
else -> {
|
||||
null
|
||||
}
|
||||
},
|
||||
isError = showError,
|
||||
singleLine = true,
|
||||
colors = if (isRecordingKey) {
|
||||
TextFieldDefaults.outlinedTextFieldColors(
|
||||
textColor = Color.Transparent,
|
||||
cursorColor = Color.Transparent,
|
||||
)
|
||||
} else {
|
||||
TextFieldDefaults.outlinedTextFieldColors()
|
||||
},
|
||||
)
|
||||
}
|
||||
FlorisIconButton(
|
||||
onClick = { requestStartRecording() },
|
||||
icon = painterResource(R.drawable.ic_pageview),
|
||||
iconColor = recordingKeyColor,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(visible = showError) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
text = stringRes(errorId).curlyFormat(
|
||||
"c_min" to KeyCode.Spec.CHARACTERS_MIN,
|
||||
"c_max" to KeyCode.Spec.CHARACTERS_MAX,
|
||||
"i_min" to KeyCode.Spec.INTERNAL_MIN,
|
||||
"i_max" to KeyCode.Spec.INTERNAL_MAX,
|
||||
),
|
||||
color = MaterialTheme.colors.error,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextKeyDataPreviewBox(
|
||||
textKeyData: TextKeyData?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val data = textKeyData ?: TextKeyData.UNSPECIFIED
|
||||
|
||||
val context = LocalContext.current
|
||||
val evaluator = remember(context) {
|
||||
object : ComputingEvaluator by DefaultComputingEvaluator {
|
||||
val keyboard = object : Keyboard() {
|
||||
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) =
|
||||
error("not implemented")
|
||||
}
|
||||
override fun context() = context
|
||||
override fun keyboard() = keyboard
|
||||
}
|
||||
}
|
||||
|
||||
val label = remember(data) { evaluator.computeLabel(data) }
|
||||
val iconId = remember(data) { evaluator.computeIconResId(data) }
|
||||
val displayName = remember(data) {
|
||||
if (data.code > 0 && AndroidVersion.ATLEAST_API24_N) {
|
||||
UCharacter.getName(data.code) ?: UCharacter.getExtendedName(data.code)
|
||||
} else {
|
||||
data.label
|
||||
}
|
||||
}
|
||||
|
||||
Row(modifier = modifier) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(end = 16.dp)
|
||||
.background(
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.12f),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
)
|
||||
.height(36.dp)
|
||||
.widthIn(min = 36.dp)
|
||||
.align(Alignment.CenterVertically),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (label != null) {
|
||||
Text(
|
||||
text = label,
|
||||
fontSize = 16.sp,
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
)
|
||||
}
|
||||
if (iconId != null) {
|
||||
Icon(
|
||||
modifier = Modifier.requiredSize(24.dp),
|
||||
painter = painterResource(iconId),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(text = displayName)
|
||||
Text(text = data.type.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,11 @@ class FlorisLocale private constructor(val base: Locale) {
|
||||
*
|
||||
* @see java.util.Locale.getDisplayLanguage
|
||||
*/
|
||||
fun displayLanguage(locale: FlorisLocale = default()): String = base.getDisplayLanguage(locale.base)
|
||||
fun displayLanguage(locale: FlorisLocale = default()): String {
|
||||
return base.getDisplayLanguage(locale.base).replaceFirstChar {
|
||||
if (it.isLowerCase()) it.titlecase(locale.base) else it.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this locale's country, localized to [locale].
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.common
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ViewFlipper
|
||||
|
||||
/**
|
||||
* Custom ViewFlipper class used to prevent an unnecessary exception to be thrown when it is
|
||||
* detached from a window.
|
||||
*
|
||||
* Based on the solution of this SO answer: https://stackoverflow.com/a/8208874/6801193
|
||||
*/
|
||||
class FlorisViewFlipper : ViewFlipper {
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
try {
|
||||
super.onDetachedFromWindow()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
stopFlipping()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ private const val IME_SERVICE_CLASS_NAME = "dev.patrickgold.florisboard.FlorisIm
|
||||
object InputMethodUtils {
|
||||
@Composable
|
||||
fun observeIsFlorisboardEnabled(
|
||||
context: Context = LocalContext.current,
|
||||
context: Context = LocalContext.current.applicationContext,
|
||||
foregroundOnly: Boolean = false,
|
||||
) = AndroidSettings.Secure.observeAsState(
|
||||
key = Settings.Secure.ENABLED_INPUT_METHODS,
|
||||
@@ -43,7 +43,7 @@ object InputMethodUtils {
|
||||
|
||||
@Composable
|
||||
fun observeIsFlorisboardSelected(
|
||||
context: Context = LocalContext.current,
|
||||
context: Context = LocalContext.current.applicationContext,
|
||||
foregroundOnly: Boolean = false,
|
||||
) = AndroidSettings.Secure.observeAsState(
|
||||
key = Settings.Secure.DEFAULT_INPUT_METHOD,
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.common
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
class RegexSerializer : KSerializer<Regex> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ThemeValue", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Regex) {
|
||||
encoder.encodeString(value.toString())
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Regex {
|
||||
return decoder.decodeString().toRegex()
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package dev.patrickgold.florisboard.common
|
||||
|
||||
import android.icu.lang.UCharacter
|
||||
import android.icu.lang.UCharacterCategory
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
|
||||
/**
|
||||
* Character codes and comments source:
|
||||
* https://www.w3.org/International/questions/qa-bidi-unicode-controls#basedirection
|
||||
@@ -40,3 +44,30 @@ object UnicodeCtrlChar {
|
||||
fun String.stripUnicodeCtrlChars(): String {
|
||||
return this.replace(UnicodeCtrlChar.Matcher, "")
|
||||
}
|
||||
|
||||
object Unicode {
|
||||
fun isNonSpacingMark(code: Int): Boolean {
|
||||
return if (AndroidVersion.ATLEAST_API24_N) {
|
||||
UCharacter.getType(code).toByte() == UCharacterCategory.NON_SPACING_MARK
|
||||
} else {
|
||||
// See: https://en.wikipedia.org/wiki/Combining_character
|
||||
// https://unicode-table.com/en/blocks/arabic/
|
||||
return when (code) {
|
||||
in 0x0300..0x036F, // Combining Diacritical Marks
|
||||
in 0x1AB0..0x1AFF, // Combining Diacritical Marks Extended
|
||||
in 0x1DC0..0x1DFF, // Combining Diacritical Marks Supplement
|
||||
in 0x20D0..0x20FF, // Combining Diacritical Marks for Symbols
|
||||
in 0xFE20..0xFE2F, // Combining Half Marks
|
||||
0x0E31, // Thai
|
||||
in 0x0E34..0x0E3A, // Thai
|
||||
in 0x0E47..0x0E4E, // Thai
|
||||
in 0x0610..0x0614, // Honorifics
|
||||
in 0x064B..0x065F, // Tashkil, Combining maddah, hamza and other
|
||||
0x0670, // Tashkil (single char)
|
||||
in 0x06D6..0x06ED, // Quranic annotation signs
|
||||
-> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,9 @@ package dev.patrickgold.florisboard.common
|
||||
import android.content.res.Resources
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
|
||||
/**
|
||||
* This file has been taken from the Android LatinIME project. Following modifications were done to
|
||||
@@ -101,22 +98,4 @@ object ViewUtils {
|
||||
fun px2dp(px: Float): Float {
|
||||
return px / (Resources.getSystem().displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
|
||||
}
|
||||
|
||||
fun setEnabled(view: View, v: Boolean) {
|
||||
view.isEnabled = v
|
||||
if (view is ViewGroup) {
|
||||
for (childView in view.children) {
|
||||
setEnabled(childView, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setVisible(view: View, v: Boolean) {
|
||||
view.isVisible = v
|
||||
if (view is ViewGroup) {
|
||||
for (childView in view.children) {
|
||||
setVisible(childView, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.common.android
|
||||
|
||||
import android.content.res.Resources
|
||||
|
||||
/**
|
||||
* Helper class for retrieving `com.android.internal.R.*` resources.
|
||||
*
|
||||
* Usage of this ids should always be done within a try..catch block, as there may be devices which have completely
|
||||
* modified system resources or something has changed in a newer Android version.
|
||||
*/
|
||||
object AndroidInternalR {
|
||||
@Suppress("ClassName")
|
||||
object string {
|
||||
val ime_action_go by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_go", "string", "android")
|
||||
}
|
||||
val ime_action_search by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_search", "string", "android")
|
||||
}
|
||||
val ime_action_send by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_send", "string", "android")
|
||||
}
|
||||
val ime_action_next by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_next", "string", "android")
|
||||
}
|
||||
val ime_action_done by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_done", "string", "android")
|
||||
}
|
||||
val ime_action_previous by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_previous", "string", "android")
|
||||
}
|
||||
val ime_action_default by lazy {
|
||||
Resources.getSystem().getIdentifier("ime_action_default", "string", "android")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ abstract class AndroidSettingsHelper(
|
||||
transform: (String?) -> R,
|
||||
): State<R> {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val context = LocalContext.current
|
||||
val context = LocalContext.current.applicationContext
|
||||
val state = remember(key) { mutableStateOf(transform(getString(context, key))) }
|
||||
DisposableEffect(lifecycleOwner.lifecycle) {
|
||||
val observer = SystemSettingsObserver(context) {
|
||||
|
||||
@@ -29,6 +29,10 @@ class SystemSettingsObserver(
|
||||
private val listener: OnSystemSettingsChangedListener,
|
||||
) : ContentObserver(Handler(context.mainLooper)) {
|
||||
|
||||
override fun deliverSelfNotifications(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
listener.onChanged()
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import dev.patrickgold.florisboard.common.kotlin.CurlyArg
|
||||
*
|
||||
* @param text The text to show in the toast popup.
|
||||
*/
|
||||
fun Context.showShortToast(text: String) {
|
||||
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
|
||||
fun Context.showShortToast(text: String): Toast {
|
||||
return Toast.makeText(this, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,9 +35,9 @@ fun Context.showShortToast(text: String) {
|
||||
*
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
*/
|
||||
fun Context.showShortToast(@StringRes id: Int) {
|
||||
fun Context.showShortToast(@StringRes id: Int): Toast {
|
||||
val text = this.stringRes(id)
|
||||
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
|
||||
return Toast.makeText(this, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,9 +47,9 @@ fun Context.showShortToast(@StringRes id: Int) {
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
* @param args The curly arguments which will be filled into the string template identified by [id].
|
||||
*/
|
||||
fun Context.showShortToast(@StringRes id: Int, vararg args: CurlyArg) {
|
||||
fun Context.showShortToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
val text = this.stringRes(id, *args)
|
||||
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
|
||||
return Toast.makeText(this, text, Toast.LENGTH_SHORT).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +57,8 @@ fun Context.showShortToast(@StringRes id: Int, vararg args: CurlyArg) {
|
||||
*
|
||||
* @param text The text to show in the toast popup.
|
||||
*/
|
||||
fun Context.showLongToast(text: String) {
|
||||
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||
fun Context.showLongToast(text: String): Toast {
|
||||
return Toast.makeText(this, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,9 +66,9 @@ fun Context.showLongToast(text: String) {
|
||||
*
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
*/
|
||||
fun Context.showLongToast(@StringRes id: Int) {
|
||||
fun Context.showLongToast(@StringRes id: Int): Toast {
|
||||
val text = this.stringRes(id)
|
||||
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||
return Toast.makeText(this, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,7 +78,7 @@ fun Context.showLongToast(@StringRes id: Int) {
|
||||
* @param id The string resource id of the text to display. Must not be 0.
|
||||
* @param args The curly arguments which will be filled into the string template identified by [id].
|
||||
*/
|
||||
fun Context.showLongToast(@StringRes id: Int, vararg args: CurlyArg) {
|
||||
fun Context.showLongToast(@StringRes id: Int, vararg args: CurlyArg): Toast {
|
||||
val text = this.stringRes(id, *args)
|
||||
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||
return Toast.makeText(this, text, Toast.LENGTH_LONG).also { it.show() }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.common.kotlin
|
||||
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class GuardedByLock<out T : Any>(@PublishedApi internal val wrapped: T) {
|
||||
@PublishedApi
|
||||
internal val lock = Mutex(locked = false)
|
||||
|
||||
suspend inline fun <R> withLock(owner: Any? = null, action: (T) -> R): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
lock.lock(owner)
|
||||
try {
|
||||
return action(wrapped)
|
||||
} finally {
|
||||
lock.unlock(owner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T : Any> guardedByLock(initializer: () -> T): GuardedByLock<T> {
|
||||
contract {
|
||||
callsInPlace(initializer, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
return GuardedByLock(initializer())
|
||||
}
|
||||
@@ -18,10 +18,15 @@ package dev.patrickgold.florisboard.ime.clipboard
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.graphics.BitmapFactory
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.media.ThumbnailUtils
|
||||
import android.provider.MediaStore
|
||||
import android.util.Size
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
@@ -38,6 +43,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Icon
|
||||
@@ -61,6 +67,7 @@ import androidx.compose.ui.text.TextStyle
|
||||
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.prefs.florisPreferenceModel
|
||||
@@ -75,6 +82,7 @@ import dev.patrickgold.florisboard.app.ui.components.safeTimes
|
||||
import dev.patrickgold.florisboard.app.ui.theme.Green500
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.common.android.AndroidKeyguardManager
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.android.showShortToast
|
||||
import dev.patrickgold.florisboard.common.android.systemService
|
||||
import dev.patrickgold.florisboard.common.observeAsNonNullState
|
||||
@@ -83,7 +91,6 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
@@ -97,6 +104,7 @@ import dev.patrickgold.florisboard.snygg.ui.solidColor
|
||||
import dev.patrickgold.florisboard.snygg.ui.spSize
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
|
||||
|
||||
private val ContentPadding = PaddingValues(horizontal = 4.dp)
|
||||
private val ItemMargin = PaddingValues(all = 6.dp)
|
||||
private val ItemPadding = PaddingValues(vertical = 8.dp, horizontal = 12.dp)
|
||||
@@ -118,18 +126,7 @@ fun ClipboardInputLayout(
|
||||
val historyEnabled by prefs.clipboard.historyEnabled.observeAsState()
|
||||
val history by clipboardManager.history.observeAsNonNullState()
|
||||
|
||||
val smartbarEnabled by prefs.smartbar.enabled.observeAsState()
|
||||
val secondaryRowEnabled by prefs.smartbar.secondaryActionsEnabled.observeAsState()
|
||||
val secondaryRowExpanded by prefs.smartbar.secondaryActionsExpanded.observeAsState()
|
||||
val secondaryRowPlacement by prefs.smartbar.secondaryActionsPlacement.observeAsState()
|
||||
val innerHeight =
|
||||
if (smartbarEnabled && secondaryRowEnabled && secondaryRowExpanded &&
|
||||
secondaryRowPlacement != SecondaryRowPlacement.OVERLAY_APP_UI
|
||||
) {
|
||||
FlorisImeSizing.smartbarHeight
|
||||
} else {
|
||||
0.dp
|
||||
} + (FlorisImeSizing.keyboardRowBaseHeight * 4)
|
||||
val innerHeight = FlorisImeSizing.keyboardUiHeight() - FlorisImeSizing.smartbarHeight
|
||||
var popupItem by remember(history) { mutableStateOf<ClipboardItem?>(null) }
|
||||
var showClearAllHistory by remember { mutableStateOf(false) }
|
||||
|
||||
@@ -194,6 +191,7 @@ fun ClipboardInputLayout(
|
||||
fun ClipItemView(
|
||||
item: ClipboardItem,
|
||||
style: SnyggPropertySet,
|
||||
contentScrollInsteadOfClip: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SnyggSurface(
|
||||
@@ -243,15 +241,65 @@ fun ClipboardInputLayout(
|
||||
fontSize = style.fontSize.spSize(),
|
||||
)
|
||||
}
|
||||
} else if (item.type == ItemType.VIDEO) {
|
||||
val id = ContentUris.parseId(item.uri!!)
|
||||
val file = ClipboardFileStorage.getFileForId(context, id)
|
||||
val bitmap = remember(id) {
|
||||
runCatching {
|
||||
check(file.exists()) { "Unable to resolve video at ${file.absolutePath}" }
|
||||
val rawBitmap = if (AndroidVersion.ATLEAST_API29_Q) {
|
||||
val dataRetriever = MediaMetadataRetriever()
|
||||
dataRetriever.setDataSource(file.absolutePath)
|
||||
val width = dataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
|
||||
val height = dataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
|
||||
ThumbnailUtils.createVideoThumbnail(file, Size(width!!.toInt(), height!!.toInt()), null)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
ThumbnailUtils.createVideoThumbnail(file.absolutePath, MediaStore.Video.Thumbnails.MINI_KIND)
|
||||
}
|
||||
checkNotNull(rawBitmap) { "Unable to decode video at ${file.absolutePath}" }
|
||||
rawBitmap.asImageBitmap()
|
||||
}
|
||||
}
|
||||
if (bitmap.isSuccess) {
|
||||
Image(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
bitmap = bitmap.getOrThrow(),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.padding(start = 4.dp, bottom = 4.dp)
|
||||
.background(Color.White, CircleShape),
|
||||
painter = painterResource(R.drawable.ic_videocam),
|
||||
contentDescription = null,
|
||||
tint = Color.Black,
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(ItemPadding),
|
||||
text = bitmap.exceptionOrNull()?.message ?: "Unknown error",
|
||||
style = TextStyle(textDirection = TextDirection.Ltr),
|
||||
color = Color.Red,
|
||||
fontSize = style.fontSize.spSize(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.run { if (contentScrollInsteadOfClip) this.florisVerticalScroll() else this }
|
||||
.padding(ItemPadding),
|
||||
text = item.stringRepresentation(),
|
||||
style = TextStyle(textDirection = TextDirection.ContentOrLtr),
|
||||
color = style.foreground.solidColor(),
|
||||
fontSize = style.fontSize.spSize(),
|
||||
maxLines = if (contentScrollInsteadOfClip) Int.MAX_VALUE else 5,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -279,7 +327,7 @@ fun ClipboardInputLayout(
|
||||
)
|
||||
FlorisStaggeredVerticalGrid(maxColumnWidth = ItemWidth) {
|
||||
for (item in history.pinned) {
|
||||
ClipItemView(item, itemStyle)
|
||||
ClipItemView(item, itemStyle, contentScrollInsteadOfClip = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +338,7 @@ fun ClipboardInputLayout(
|
||||
)
|
||||
FlorisStaggeredVerticalGrid(maxColumnWidth = ItemWidth) {
|
||||
for (item in history.recent) {
|
||||
ClipItemView(item, itemStyle)
|
||||
ClipItemView(item, itemStyle, contentScrollInsteadOfClip = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,7 +349,7 @@ fun ClipboardInputLayout(
|
||||
)
|
||||
FlorisStaggeredVerticalGrid(maxColumnWidth = ItemWidth) {
|
||||
for (item in history.other) {
|
||||
ClipItemView(item, itemStyle)
|
||||
ClipItemView(item, itemStyle, contentScrollInsteadOfClip = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,6 +369,7 @@ fun ClipboardInputLayout(
|
||||
modifier = Modifier.widthIn(max = ItemWidth),
|
||||
item = popupItem!!,
|
||||
style = itemStyle,
|
||||
contentScrollInsteadOfClip = true,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -34,7 +34,8 @@ private const val CLIPBOARD_FILES_TABLE = "clipboard_files"
|
||||
|
||||
enum class ItemType(val value: Int) {
|
||||
TEXT(1),
|
||||
IMAGE(2);
|
||||
IMAGE(2),
|
||||
VIDEO(3);
|
||||
|
||||
companion object {
|
||||
fun fromInt(value : Int) : ItemType {
|
||||
@@ -85,20 +86,25 @@ data class ClipboardItem(
|
||||
* Returns a new ClipboardItem based on a ClipData.
|
||||
*
|
||||
* @param data The ClipData to clone.
|
||||
* @param cloneUri Whether to store the image using [ClipboardImagesProvider].
|
||||
* @param cloneUri Whether to store the image using [ClipboardMediaProvider].
|
||||
*/
|
||||
fun fromClipData(context: Context, data: ClipData, cloneUri: Boolean) : ClipboardItem {
|
||||
val dataItem = data.getItemAt(0)
|
||||
val type = when {
|
||||
dataItem?.uri != null && data.description.hasMimeType("image/*") -> ItemType.IMAGE
|
||||
dataItem?.uri != null && data.description.hasMimeType("video/*") -> ItemType.VIDEO
|
||||
else -> ItemType.TEXT
|
||||
}
|
||||
|
||||
val uri = if (type == ItemType.IMAGE) {
|
||||
if (dataItem.uri.authority == ClipboardImagesProvider.AUTHORITY || !cloneUri) {
|
||||
val uri = if (type == ItemType.IMAGE || type == ItemType.VIDEO) {
|
||||
if (dataItem.uri.authority == ClipboardMediaProvider.AUTHORITY || !cloneUri) {
|
||||
dataItem.uri
|
||||
} else {
|
||||
var displayName = "Image"
|
||||
var displayName = when (type) {
|
||||
ItemType.IMAGE -> "Image"
|
||||
ItemType.VIDEO -> "Video"
|
||||
else -> "Unknown"
|
||||
}
|
||||
tryOrNull {
|
||||
context.contentResolver.query(dataItem.uri, MEDIA_PROJECTION)?.use { cursor ->
|
||||
val displayNameColumn = cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)
|
||||
@@ -109,17 +115,23 @@ data class ClipboardItem(
|
||||
}
|
||||
val values = ContentValues(3).apply {
|
||||
put(OpenableColumns.DISPLAY_NAME, displayName)
|
||||
put(ClipboardImagesProvider.Columns.ImageUri, dataItem.uri.toString())
|
||||
put(ClipboardImagesProvider.Columns.MimeTypes, data.description.filterMimeTypes("*/*").joinToString(","))
|
||||
put(ClipboardMediaProvider.Columns.MediaUri, dataItem.uri.toString())
|
||||
put(ClipboardMediaProvider.Columns.MimeTypes, data.description.filterMimeTypes("*/*").joinToString(","))
|
||||
}
|
||||
context.contentResolver.insert(ClipboardImagesProvider.IMAGE_CLIPS_URI, values)
|
||||
context.contentResolver.insert(when (type) {
|
||||
ItemType.IMAGE -> ClipboardMediaProvider.IMAGE_CLIPS_URI
|
||||
ItemType.VIDEO -> ClipboardMediaProvider.VIDEO_CLIPS_URI
|
||||
else -> error("Impossible.")
|
||||
}, values)
|
||||
}
|
||||
} else { null }
|
||||
|
||||
val text = dataItem.coerceToText(context).toString()
|
||||
val text = dataItem.text?.toString()
|
||||
val mimeTypes = when (type) {
|
||||
ItemType.IMAGE -> Array(data.description.mimeTypeCount) { data.description.getMimeType(it) }
|
||||
ItemType.TEXT -> TEXT_PLAIN
|
||||
ItemType.IMAGE, ItemType.VIDEO -> {
|
||||
Array(data.description.mimeTypeCount) { data.description.getMimeType(it) }
|
||||
}
|
||||
}
|
||||
|
||||
return ClipboardItem(0, type, text, uri, System.currentTimeMillis(), false, mimeTypes)
|
||||
@@ -130,7 +142,7 @@ data class ClipboardItem(
|
||||
if (other == null) return false
|
||||
return when (type) {
|
||||
ItemType.TEXT -> text == other.getItemAt(0).text
|
||||
ItemType.IMAGE -> uri == other.getItemAt(0).uri
|
||||
ItemType.IMAGE, ItemType.VIDEO -> uri == other.getItemAt(0).uri
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,12 +151,12 @@ data class ClipboardItem(
|
||||
*/
|
||||
fun toClipData(context: Context): ClipData {
|
||||
return when (type) {
|
||||
ItemType.IMAGE -> {
|
||||
ClipData.newUri(context.contentResolver, FLORIS_CLIP_LABEL, uri)
|
||||
}
|
||||
ItemType.TEXT -> {
|
||||
ClipData.newPlainText(FLORIS_CLIP_LABEL, text)
|
||||
}
|
||||
ItemType.IMAGE, ItemType.VIDEO -> {
|
||||
ClipData.newUri(context.contentResolver, FLORIS_CLIP_LABEL, uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import dev.patrickgold.florisboard.res.io.FsFile
|
||||
import dev.patrickgold.florisboard.res.io.subFile
|
||||
|
||||
/**
|
||||
* Backend helper object which is used by [ClipboardImagesProvider] to serve content.
|
||||
* Backend helper object which is used by [ClipboardMediaProvider] to serve content.
|
||||
*/
|
||||
object ClipboardFileStorage {
|
||||
private val Context.clipboardFilesDir: FsFile
|
||||
|
||||
@@ -30,12 +30,12 @@ import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Allows apps to access images on the clipboard.
|
||||
* Allows apps to access images and videos on the clipboard.
|
||||
*
|
||||
* This is sometimes called by the UI thread, so all functions are non blocking.
|
||||
* Database accesses are performed async.
|
||||
*/
|
||||
class ClipboardImagesProvider : ContentProvider() {
|
||||
class ClipboardMediaProvider : ContentProvider() {
|
||||
private var clipboardFilesDao: ClipboardFilesDao? = null
|
||||
private val cachedFileInfos: HashMap<Long, ClipboardFileInfo> = hashMapOf()
|
||||
private val ioScope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
@@ -43,18 +43,23 @@ class ClipboardImagesProvider : ContentProvider() {
|
||||
companion object {
|
||||
const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.provider.clipboard"
|
||||
val IMAGE_CLIPS_URI: Uri = Uri.parse("content://$AUTHORITY/clips/images")
|
||||
val VIDEO_CLIPS_URI: Uri = Uri.parse("content://$AUTHORITY/clips/videos")
|
||||
|
||||
private const val IMAGE_CLIP_ITEM = 0
|
||||
private const val IMAGE_CLIPS_TABLE = 1
|
||||
private const val VIDEO_CLIP_ITEM = 2
|
||||
private const val VIDEO_CLIPS_TABLE = 3
|
||||
|
||||
val matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
|
||||
private val Matcher = UriMatcher(UriMatcher.NO_MATCH).apply {
|
||||
addURI(AUTHORITY, "clips/images/#", IMAGE_CLIP_ITEM)
|
||||
addURI(AUTHORITY, "clips/images", IMAGE_CLIPS_TABLE)
|
||||
addURI(AUTHORITY, "clips/videos/#", VIDEO_CLIP_ITEM)
|
||||
addURI(AUTHORITY, "clips/videos", VIDEO_CLIPS_TABLE)
|
||||
}
|
||||
}
|
||||
|
||||
object Columns {
|
||||
const val ImageUri = "image_uri"
|
||||
const val MediaUri = "media_uri"
|
||||
const val MimeTypes = "mime_types"
|
||||
}
|
||||
|
||||
@@ -85,16 +90,21 @@ class ClipboardImagesProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
override fun getType(uri: Uri): String? {
|
||||
return when (matcher.match(uri)) {
|
||||
IMAGE_CLIP_ITEM -> cachedFileInfos.getOrDefault(ContentUris.parseId(uri), null)?.mimeTypes?.getOrNull(0)
|
||||
return when (Matcher.match(uri)) {
|
||||
IMAGE_CLIP_ITEM, VIDEO_CLIP_ITEM -> {
|
||||
cachedFileInfos.getOrDefault(ContentUris.parseId(uri), null)?.mimeTypes?.getOrNull(0)
|
||||
}
|
||||
IMAGE_CLIPS_TABLE -> "${ContentResolver.CURSOR_DIR_BASE_TYPE}/vnd.florisboard.image_clip_table"
|
||||
VIDEO_CLIPS_TABLE -> "${ContentResolver.CURSOR_DIR_BASE_TYPE}/vnd.florisboard.video_clip_table"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStreamTypes(uri: Uri, mimeTypeFilter: String): Array<String>? {
|
||||
return when (matcher.match(uri)) {
|
||||
IMAGE_CLIP_ITEM -> cachedFileInfos.getOrDefault(ContentUris.parseId(uri), null)?.mimeTypes
|
||||
return when (Matcher.match(uri)) {
|
||||
IMAGE_CLIP_ITEM, VIDEO_CLIP_ITEM -> {
|
||||
cachedFileInfos.getOrDefault(ContentUris.parseId(uri), null)?.mimeTypes
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -108,12 +118,12 @@ class ClipboardImagesProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri {
|
||||
when (matcher.match(uri)) {
|
||||
IMAGE_CLIPS_TABLE -> {
|
||||
when (val m = Matcher.match(uri)) {
|
||||
IMAGE_CLIPS_TABLE, VIDEO_CLIPS_TABLE -> {
|
||||
return try {
|
||||
values as ContentValues
|
||||
val imageUri = Uri.parse(values.getAsString(Columns.ImageUri))
|
||||
val id = ClipboardFileStorage.cloneUri(context!!, imageUri)
|
||||
val mediaUri = Uri.parse(values.getAsString(Columns.MediaUri))
|
||||
val id = ClipboardFileStorage.cloneUri(context!!, mediaUri)
|
||||
val size = ClipboardFileStorage.getFileForId(context!!, id).length()
|
||||
val mimeTypes = values.getAsString(Columns.MimeTypes).split(",").toTypedArray()
|
||||
val displayName = values.getAsString(OpenableColumns.DISPLAY_NAME)
|
||||
@@ -122,7 +132,11 @@ class ClipboardImagesProvider : ContentProvider() {
|
||||
ioScope.launch {
|
||||
clipboardFilesDao?.insert(fileInfo)
|
||||
}
|
||||
ContentUris.withAppendedId(IMAGE_CLIPS_URI, id)
|
||||
if (m == IMAGE_CLIPS_TABLE) {
|
||||
ContentUris.withAppendedId(IMAGE_CLIPS_URI, id)
|
||||
} else {
|
||||
ContentUris.withAppendedId(VIDEO_CLIPS_URI, id)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
flogError { e.message.toString() }
|
||||
uri.buildUpon().appendPath("0").build()
|
||||
@@ -133,8 +147,8 @@ class ClipboardImagesProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
when (matcher.match(uri)) {
|
||||
IMAGE_CLIP_ITEM -> {
|
||||
when (Matcher.match(uri)) {
|
||||
IMAGE_CLIP_ITEM, VIDEO_CLIP_ITEM -> {
|
||||
val id = ContentUris.parseId(uri)
|
||||
ClipboardFileStorage.deleteById(context!!, id)
|
||||
cachedFileInfos.remove(id)
|
||||
@@ -29,6 +29,9 @@ import android.view.inputmethod.ExtractedText
|
||||
import android.view.inputmethod.ExtractedTextRequest
|
||||
import android.view.inputmethod.InputBinding
|
||||
import android.view.inputmethod.InputConnection
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat
|
||||
@@ -92,8 +95,7 @@ class EditorInstance(private val ims: InputMethodService) {
|
||||
get() = if (isInputBindingActive) ims.currentInputBinding else null
|
||||
val inputConnection: InputConnection?
|
||||
get() = if (isInputBindingActive) ims.currentInputConnection else null
|
||||
val editorInfo: EditorInfo?
|
||||
get() = if (isInputBindingActive && ims.currentInputStarted) ims.currentInputEditorInfo else null
|
||||
var editorInfo: EditorInfo? by mutableStateOf(null)
|
||||
|
||||
val cursorCapsMode: InputAttributes.CapsMode
|
||||
get() {
|
||||
@@ -172,6 +174,7 @@ class EditorInstance(private val ims: InputMethodService) {
|
||||
|
||||
fun startInput(info: EditorInfo) {
|
||||
flogInfo(LogTopic.EDITOR_INSTANCE) { "info=${info.debugSummarize()}" }
|
||||
editorInfo = info
|
||||
if (AndroidVersion.ATLEAST_API25_N_MR1) {
|
||||
contentMimeTypes = info.contentMimeTypes
|
||||
}
|
||||
@@ -191,6 +194,7 @@ class EditorInstance(private val ims: InputMethodService) {
|
||||
|
||||
fun startInputView(info: EditorInfo) {
|
||||
flogInfo(LogTopic.EDITOR_INSTANCE) { "info=${info.debugSummarize()}" }
|
||||
editorInfo = info
|
||||
val keyboardMode = when (activeState.inputAttributes.type) {
|
||||
InputAttributes.Type.NUMBER -> {
|
||||
activeState.keyVariation = KeyVariation.NORMAL
|
||||
@@ -248,10 +252,12 @@ class EditorInstance(private val ims: InputMethodService) {
|
||||
|
||||
fun finishInputView() {
|
||||
flogInfo(LogTopic.EDITOR_INSTANCE) { "(no args)" }
|
||||
editorInfo = null
|
||||
}
|
||||
|
||||
fun finishInput() {
|
||||
flogInfo(LogTopic.EDITOR_INSTANCE) { "(no args)" }
|
||||
editorInfo = null
|
||||
val ic = inputConnection ?: return
|
||||
ic.requestCursorUpdates(CURSOR_UPDATE_DISABLED)
|
||||
}
|
||||
@@ -400,14 +406,17 @@ class EditorInstance(private val ims: InputMethodService) {
|
||||
if (item == null) return false
|
||||
val mimeTypes = item.mimeTypes
|
||||
return when (item.type) {
|
||||
ItemType.IMAGE -> {
|
||||
ItemType.TEXT -> {
|
||||
commitText(item.text.toString())
|
||||
}
|
||||
ItemType.IMAGE, ItemType.VIDEO -> {
|
||||
item.uri ?: return false
|
||||
val id = ContentUris.parseId(item.uri)
|
||||
val file = ClipboardFileStorage.getFileForId(ims, id)
|
||||
if (!file.exists()) return false
|
||||
val inputContentInfo = InputContentInfoCompat(
|
||||
item.uri,
|
||||
ClipDescription("clipboard image", mimeTypes),
|
||||
ClipDescription("clipboard media file", mimeTypes),
|
||||
null,
|
||||
)
|
||||
val ic = inputConnection ?: return false
|
||||
@@ -424,9 +433,6 @@ class EditorInstance(private val ims: InputMethodService) {
|
||||
}
|
||||
InputConnectionCompat.commitContent(ic, editorInfo!!, inputContentInfo, flags, null)
|
||||
}
|
||||
ItemType.TEXT -> {
|
||||
commitText(item.text.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,12 @@ fun ComputingEvaluator.computeIconResId(data: KeyData): Int? {
|
||||
KeyCode.ARROW_RIGHT -> {
|
||||
R.drawable.ic_keyboard_arrow_right
|
||||
}
|
||||
KeyCode.ARROW_UP -> {
|
||||
R.drawable.ic_keyboard_arrow_up
|
||||
}
|
||||
KeyCode.ARROW_DOWN -> {
|
||||
R.drawable.ic_keyboard_arrow_down
|
||||
}
|
||||
KeyCode.CLIPBOARD_COPY -> {
|
||||
R.drawable.ic_content_copy
|
||||
}
|
||||
|
||||
@@ -31,9 +31,10 @@ import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.common.ViewUtils
|
||||
import dev.patrickgold.florisboard.common.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationLandscape
|
||||
import dev.patrickgold.florisboard.common.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
|
||||
private val LocalKeyboardRowBaseHeight = staticCompositionLocalOf { 65.dp }
|
||||
@@ -50,6 +51,28 @@ object FlorisImeSizing {
|
||||
@ReadOnlyComposable
|
||||
get() = LocalSmartbarHeight.current
|
||||
|
||||
@Composable
|
||||
fun keyboardUiHeight(): Dp {
|
||||
val prefs by florisPreferenceModel()
|
||||
val numberRowEnabled by prefs.keyboard.numberRow.observeAsState()
|
||||
val smartbarEnabled by prefs.smartbar.enabled.observeAsState()
|
||||
val secondaryRowEnabled by prefs.smartbar.secondaryActionsEnabled.observeAsState()
|
||||
val secondaryRowExpanded by prefs.smartbar.secondaryActionsExpanded.observeAsState()
|
||||
val secondaryRowPlacement by prefs.smartbar.secondaryActionsPlacement.observeAsState()
|
||||
val height =
|
||||
if (smartbarEnabled) {
|
||||
if (secondaryRowEnabled && secondaryRowExpanded &&
|
||||
secondaryRowPlacement != SecondaryRowPlacement.OVERLAY_APP_UI) {
|
||||
smartbarHeight * 2
|
||||
} else {
|
||||
smartbarHeight
|
||||
}
|
||||
} else {
|
||||
0.dp
|
||||
} + (keyboardRowBaseHeight * (if (numberRowEnabled) 5 else 4))
|
||||
return height
|
||||
}
|
||||
|
||||
object Static {
|
||||
var keyboardRowBaseHeightPx: Int = 0
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.inputmethodservice.InputMethodService
|
||||
import android.media.AudioManager
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.os.VibratorManager
|
||||
import android.provider.Settings
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -33,6 +34,7 @@ import dev.patrickgold.florisboard.debug.flogDebug
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import dev.patrickgold.florisboard.common.android.systemServiceOrNull
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@@ -50,19 +52,19 @@ class InputFeedbackController private constructor(private val ims: InputMethodSe
|
||||
|
||||
@Composable
|
||||
fun hasAmplitudeControl(): Boolean {
|
||||
val vibrator = LocalContext.current.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator
|
||||
val vibrator = LocalContext.current.systemVibratorOrNull()
|
||||
return when {
|
||||
AndroidVersion.ATLEAST_API26_O -> vibrator?.hasAmplitudeControl() ?: false
|
||||
AndroidVersion.ATLEAST_API26_O -> vibrator != null && vibrator.hasAmplitudeControl()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun generateVibrationStrengthErrorSummary(): String? {
|
||||
val vibrator = LocalContext.current.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator
|
||||
val vibrator = LocalContext.current.systemVibratorOrNull()
|
||||
return when {
|
||||
AndroidVersion.ATLEAST_API26_O -> when {
|
||||
!(vibrator?.hasAmplitudeControl() ?: false) -> {
|
||||
vibrator == null || !vibrator.hasAmplitudeControl() -> {
|
||||
stringRes(R.string.pref__input_feedback__haptic_vibration_strength__summary_no_amplitude_ctrl)
|
||||
}
|
||||
else -> null
|
||||
@@ -72,12 +74,20 @@ class InputFeedbackController private constructor(private val ims: InputMethodSe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.systemVibratorOrNull(): Vibrator? {
|
||||
return if (AndroidVersion.ATLEAST_API31_S) {
|
||||
this.systemServiceOrNull(VibratorManager::class)?.defaultVibrator
|
||||
} else {
|
||||
this.systemServiceOrNull(Vibrator::class)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
|
||||
private val audioManager = ims.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
|
||||
private val vibrator = ims.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator
|
||||
private val audioManager = ims.systemServiceOrNull(AudioManager::class)
|
||||
private val vibrator = ims.systemVibratorOrNull()
|
||||
private val contentResolver = ims.contentResolver
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
|
||||
|
||||
@@ -129,6 +129,11 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
prefs.keyboard.utilityKeyEnabled.observeForever {
|
||||
updateRenderInfo()
|
||||
}
|
||||
prefs.glide.enabled.observeForever { enabled ->
|
||||
if (enabled) {
|
||||
glideTypingManager.setWordData(subtypeManager.activeSubtype())
|
||||
}
|
||||
}
|
||||
activeState.observeForever {
|
||||
updateRenderInfo()
|
||||
}
|
||||
@@ -282,7 +287,7 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
|
||||
/**
|
||||
* Changes a word to the current case.
|
||||
* eg if [KeyboardState.capsLock] is true, abc -> ABC
|
||||
* eg if [KeyboardState.isUppercase] is true, abc -> ABC
|
||||
* if [caps] is true, abc -> Abc
|
||||
* otherwise , abc -> abc
|
||||
*/
|
||||
|
||||
@@ -98,8 +98,6 @@ class KeyboardState private constructor(initValue: ULong) : LiveData<KeyboardSta
|
||||
const val M_IME_UI_MODE: ULong = 0x07u
|
||||
const val O_IME_UI_MODE: Int = 24
|
||||
|
||||
const val F_CAPS: ULong = 0x00000100u
|
||||
const val F_CAPS_LOCK: ULong = 0x00000200u
|
||||
const val F_IS_SELECTION_MODE: ULong = 0x00000400u
|
||||
const val F_IS_MANUAL_SELECTION_MODE: ULong = 0x00000800u
|
||||
const val F_IS_MANUAL_SELECTION_MODE_START: ULong = 0x00001000u
|
||||
@@ -282,16 +280,6 @@ class KeyboardState private constructor(initValue: ULong) : LiveData<KeyboardSta
|
||||
get() = if (getFlag(F_IS_RTL_LAYOUT_DIRECTION)) LayoutDirection.Rtl else LayoutDirection.Ltr
|
||||
set(v) { setFlag(F_IS_RTL_LAYOUT_DIRECTION, v == LayoutDirection.Rtl) }
|
||||
|
||||
@Deprecated("Use inputMode and/or isLowercase/isUppercase")
|
||||
var shiftLock: Boolean
|
||||
get() = getFlag(F_CAPS)
|
||||
set(v) { setFlag(F_CAPS, v) }
|
||||
|
||||
@Deprecated("Use inputMode and/or isLowercase/isUppercase")
|
||||
var capsLock: Boolean
|
||||
get() = getFlag(F_CAPS_LOCK)
|
||||
set(v) { setFlag(F_CAPS_LOCK, v) }
|
||||
|
||||
val isLowercase: Boolean
|
||||
get() = inputMode == InputMode.NORMAL
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Patrick Goldinger
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package dev.patrickgold.florisboard.ime.lifecycle
|
||||
|
||||
import android.inputmethodservice.InputMethodService
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
@@ -63,13 +62,23 @@ open class LifecycleInputMethodService : InputMethodService(),
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onCreateInputView(): View? {
|
||||
fun installViewTreeOwners() {
|
||||
val decorView = window!!.window!!.decorView
|
||||
ViewTreeLifecycleOwner.set(decorView, this)
|
||||
ViewTreeViewModelStoreOwner.set(decorView, this)
|
||||
ViewTreeSavedStateRegistryOwner.set(decorView, this)
|
||||
return null
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onWindowShown() {
|
||||
super.onWindowShown()
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
override fun onWindowHidden() {
|
||||
super.onWindowHidden()
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
|
||||
@@ -46,7 +46,6 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.core.InputEventDispatcher
|
||||
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
@@ -54,12 +53,10 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiPaletteView
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.parseRawEmojiSpecsFile
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.snygg.ui.SnyggSurface
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -68,36 +65,19 @@ import kotlinx.coroutines.launch
|
||||
fun MediaInputLayout(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
|
||||
val smartbarEnabled by prefs.smartbar.enabled.observeAsState()
|
||||
val secondaryRowEnabled by prefs.smartbar.secondaryActionsEnabled.observeAsState()
|
||||
val secondaryRowExpanded by prefs.smartbar.secondaryActionsExpanded.observeAsState()
|
||||
val secondaryRowPlacement by prefs.smartbar.secondaryActionsPlacement.observeAsState()
|
||||
val height =
|
||||
if (smartbarEnabled) {
|
||||
if (secondaryRowEnabled && secondaryRowExpanded &&
|
||||
secondaryRowPlacement != SecondaryRowPlacement.OVERLAY_APP_UI) {
|
||||
FlorisImeSizing.smartbarHeight * 2
|
||||
} else {
|
||||
FlorisImeSizing.smartbarHeight
|
||||
}
|
||||
} else {
|
||||
0.dp
|
||||
} + (FlorisImeSizing.keyboardRowBaseHeight * 4)
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(height),
|
||||
) {
|
||||
EmojiPaletteView(
|
||||
modifier = Modifier.weight(1f),
|
||||
fullEmojiMappings = parseRawEmojiSpecsFile(context, "ime/media/emoji/root.txt"),
|
||||
)
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(FlorisImeSizing.keyboardUiHeight()),
|
||||
) {
|
||||
EmojiPaletteView(
|
||||
modifier = Modifier.weight(1f),
|
||||
fullEmojiMappings = parseRawEmojiSpecsFile(context, "ime/media/emoji/root.txt"),
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -85,7 +85,6 @@ import dev.patrickgold.florisboard.common.android.showShortToast
|
||||
import dev.patrickgold.florisboard.common.kotlin.tryOrNull
|
||||
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.fontSizeMultiplier
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
@@ -324,6 +323,7 @@ private fun EmojiKey(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = base.value,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
color = contentColor,
|
||||
fontSize = fontSize,
|
||||
)
|
||||
if (variations.isNotEmpty()) {
|
||||
@@ -398,6 +398,7 @@ private fun EmojiVariationsPopup(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
text = emoji.value,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
color = popupStyle.foreground.solidColor(default = FlorisImeTheme.fallbackContentColor()),
|
||||
fontSize = popupStyle.fontSize.spSize(default = EmojiDefaultFontSize) safeTimes fontSizeMultiplier,
|
||||
)
|
||||
}
|
||||
@@ -412,6 +413,7 @@ fun EmojiText(
|
||||
text: String,
|
||||
emojiCompatInstance: EmojiCompat?,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = Color.Black,
|
||||
fontSize: TextUnit = EmojiDefaultFontSize,
|
||||
) {
|
||||
if (emojiCompatInstance != null) {
|
||||
@@ -420,7 +422,7 @@ fun EmojiText(
|
||||
factory = { context ->
|
||||
EmojiTextView(context).also {
|
||||
it.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize.value)
|
||||
it.setTextColor(Color.Black.toArgb())
|
||||
it.setTextColor(color.toArgb())
|
||||
}
|
||||
},
|
||||
update = { view ->
|
||||
@@ -433,7 +435,7 @@ fun EmojiText(
|
||||
factory = { context ->
|
||||
TextView(context).also {
|
||||
it.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize.value)
|
||||
it.setTextColor(Color.Black.toArgb())
|
||||
it.setTextColor(color.toArgb())
|
||||
}
|
||||
},
|
||||
update = { view ->
|
||||
|
||||
@@ -40,13 +40,13 @@ fun TextInputLayout(
|
||||
|
||||
val renderInfo by keyboardManager.renderInfo.observeAsNonNullState()
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
) {
|
||||
Smartbar()
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
) {
|
||||
Smartbar()
|
||||
TextKeyboardLayout(
|
||||
renderInfo = renderInfo,
|
||||
)
|
||||
|
||||
@@ -95,6 +95,10 @@ class HangulUnicode : Composer {
|
||||
val tple = medialComp[medials[med]]
|
||||
return Pair(1, "${syllable(ini, medials.indexOf(tple!![1][tple[0].indexOf(c)]), 0)}")
|
||||
}
|
||||
} else if (lastChar in medialComp.keys && medialComp[lastChar]?.get(0)?.contains(c) == true) { // medial+final
|
||||
return Pair(1, ""+ medialComp[lastChar]?.get(1)!![medialComp[lastChar]?.get(0)!!.indexOf(c)]);
|
||||
} else if (lastChar in finalComp.keys && finalComp[lastChar]?.get(0)?.contains(c) == true) { // final+final
|
||||
return Pair(1, ""+ finalComp[lastChar]?.get(1)!![finalComp[lastChar]?.get(0)!!.indexOf(c)]);
|
||||
}
|
||||
|
||||
return Pair(0, ""+c)
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.patrickgold.florisboard.ime.text.gestures
|
||||
import android.content.Context
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.assetManager
|
||||
import dev.patrickgold.florisboard.common.kotlin.guardedByLock
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionList
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKey
|
||||
@@ -12,7 +13,7 @@ import dev.patrickgold.florisboard.res.FlorisRef
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONObject
|
||||
@@ -22,7 +23,7 @@ import kotlin.math.min
|
||||
* Handles the [GlideTypingClassifier]. Basically responsible for linking [GlideTypingGesture.Detector]
|
||||
* with [GlideTypingClassifier].
|
||||
*/
|
||||
class GlideTypingManager(context: Context) : GlideTypingGesture.Listener, CoroutineScope by MainScope() {
|
||||
class GlideTypingManager(context: Context) : GlideTypingGesture.Listener {
|
||||
companion object {
|
||||
private const val MAX_SUGGESTION_COUNT = 8
|
||||
}
|
||||
@@ -33,9 +34,10 @@ class GlideTypingManager(context: Context) : GlideTypingGesture.Listener, Corout
|
||||
private val nlpManager by context.nlpManager()
|
||||
private val subtypeManager by context.subtypeManager()
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
private var glideTypingClassifier = StatisticalGlideTypingClassifier()
|
||||
private var lastTime = System.currentTimeMillis()
|
||||
private val wordDataCache = hashMapOf<String, Int>()
|
||||
private val wordDataCache = guardedByLock { hashMapOf<String, Int>() }
|
||||
|
||||
override fun onGlideComplete(data: GlideTypingGesture.Detector.PointerData) {
|
||||
updateSuggestionsAsync(MAX_SUGGESTION_COUNT, true) {
|
||||
@@ -72,15 +74,16 @@ class GlideTypingManager(context: Context) : GlideTypingGesture.Listener, Corout
|
||||
* Set the word data for the internal gesture classifier
|
||||
*/
|
||||
fun setWordData(subtype: Subtype) {
|
||||
launch(Dispatchers.Default) {
|
||||
if (wordDataCache.isEmpty()) {
|
||||
// FIXME: get this info from dictionary.
|
||||
val data = assetManager.loadTextAsset(FlorisRef.assets("ime/dict/data.json"))
|
||||
.getOrThrow()
|
||||
val json = JSONObject(data)
|
||||
wordDataCache.putAll(json.keys().asSequence().map { Pair(it, json.getInt(it)) })
|
||||
scope.launch(Dispatchers.Default) {
|
||||
wordDataCache.withLock { wordDataCache ->
|
||||
if (wordDataCache.isEmpty()) {
|
||||
// FIXME: get this info from dictionary.
|
||||
val data = assetManager.loadTextAsset(FlorisRef.assets("ime/dict/data.json")).getOrThrow()
|
||||
val json = JSONObject(data)
|
||||
wordDataCache.putAll(json.keys().asSequence().map { it to json.getInt(it) })
|
||||
}
|
||||
glideTypingClassifier.setWordData(wordDataCache, subtype)
|
||||
}
|
||||
glideTypingClassifier.setWordData(wordDataCache, subtype)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +101,7 @@ class GlideTypingManager(context: Context) : GlideTypingGesture.Listener, Corout
|
||||
return
|
||||
}
|
||||
|
||||
launch(Dispatchers.Default) {
|
||||
scope.launch(Dispatchers.Default) {
|
||||
val suggestions = glideTypingClassifier.getSuggestions(MAX_SUGGESTION_COUNT, true)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
@@ -124,7 +124,7 @@ class StatisticalGlideTypingClassifier : GlideTypingClassifier {
|
||||
return
|
||||
}
|
||||
|
||||
this.words = words.keys
|
||||
this.words = words.keys.toSet()
|
||||
this.wordFrequencies = words
|
||||
|
||||
this.wordDataSubtype = subtype
|
||||
|
||||
@@ -226,7 +226,21 @@ class TextKey(override val data: AbstractKeyData) : Key(data) {
|
||||
foregroundDrawableId = evaluator.computeIconResId(computedData)
|
||||
|
||||
val data = computedData
|
||||
if (data.type == KeyType.CHARACTER && data.code != KeyCode.SPACE && data.code != KeyCode.CJK_SPACE
|
||||
if (data.type == KeyType.NUMERIC && evaluator.keyboard().mode == KeyboardMode.PHONE) {
|
||||
hintedLabel = when (data.code) {
|
||||
48 /* 0 */ -> "+"
|
||||
49 /* 1 */ -> ""
|
||||
50 /* 2 */ -> "ABC"
|
||||
51 /* 3 */ -> "DEF"
|
||||
52 /* 4 */ -> "GHI"
|
||||
53 /* 5 */ -> "JKL"
|
||||
54 /* 6 */ -> "MNO"
|
||||
55 /* 7 */ -> "PQRS"
|
||||
56 /* 8 */ -> "TUV"
|
||||
57 /* 9 */ -> "WXYZ"
|
||||
else -> null
|
||||
}
|
||||
} else if (data.type == KeyType.CHARACTER && data.code != KeyCode.SPACE && data.code != KeyCode.CJK_SPACE
|
||||
&& data.code != KeyCode.HALF_SPACE && data.code != KeyCode.KESHIDA || data.type == KeyType.NUMERIC
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package dev.patrickgold.florisboard.ime.text.keyboard
|
||||
|
||||
import dev.patrickgold.florisboard.common.FlorisLocale
|
||||
import dev.patrickgold.florisboard.common.Unicode
|
||||
import dev.patrickgold.florisboard.common.kotlin.lowercase
|
||||
import dev.patrickgold.florisboard.common.kotlin.uppercase
|
||||
import dev.patrickgold.florisboard.ime.keyboard.AbstractKeyData
|
||||
@@ -25,7 +26,9 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.popup.PopupSet
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyType
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
|
||||
/**
|
||||
* Data class which describes a single key and its attributes.
|
||||
@@ -60,9 +63,7 @@ class TextKeyData(
|
||||
override fun asString(isForDisplay: Boolean): String {
|
||||
return buildString {
|
||||
if (isForDisplay || code == KeyCode.URI_COMPONENT_TLD || code < KeyCode.SPACE) {
|
||||
// Combining Diacritical Marks
|
||||
// See: https://en.wikipedia.org/wiki/Combining_Diacritical_Marks
|
||||
if (code in 0x0300..0x036F && !label.startsWith("◌")) {
|
||||
if (Unicode.isNonSpacingMark(code) && !label.startsWith("◌")) {
|
||||
append("◌")
|
||||
}
|
||||
append(label)
|
||||
@@ -76,8 +77,84 @@ class TextKeyData(
|
||||
return "${TextKeyData::class.simpleName} { type=$type code=$code label=\"$label\" groupId=$groupId }"
|
||||
}
|
||||
|
||||
@Suppress("UNUSED")
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
companion object {
|
||||
fun getCodeInfoAsTextKeyData(code: Int): TextKeyData? {
|
||||
return if (code <= 0) {
|
||||
InternalKeys.find { it.code == code }
|
||||
} else {
|
||||
TextKeyData(
|
||||
type = KeyType.CHARACTER,
|
||||
code = code,
|
||||
label = buildString {
|
||||
try {
|
||||
appendCodePoint(code)
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: find better solution than to hand define array of below keys...
|
||||
private val InternalKeys by lazy {
|
||||
listOf(
|
||||
UNSPECIFIED,
|
||||
SPACE,
|
||||
CTRL,
|
||||
CTRL_LOCK,
|
||||
ALT,
|
||||
ALT_LOCK,
|
||||
FN,
|
||||
FN_LOCK,
|
||||
DELETE,
|
||||
DELETE_WORD,
|
||||
FORWARD_DELETE,
|
||||
FORWARD_DELETE_WORD,
|
||||
SHIFT,
|
||||
SHIFT_LOCK,
|
||||
CAPS_LOCK,
|
||||
ARROW_LEFT,
|
||||
ARROW_RIGHT,
|
||||
ARROW_UP,
|
||||
ARROW_DOWN,
|
||||
MOVE_START_OF_PAGE,
|
||||
MOVE_END_OF_PAGE,
|
||||
MOVE_START_OF_LINE,
|
||||
MOVE_END_OF_LINE,
|
||||
CLIPBOARD_COPY,
|
||||
CLIPBOARD_CUT,
|
||||
CLIPBOARD_PASTE,
|
||||
CLIPBOARD_SELECT,
|
||||
CLIPBOARD_SELECT_ALL,
|
||||
CLIPBOARD_CLEAR_HISTORY,
|
||||
CLIPBOARD_CLEAR_FULL_HISTORY,
|
||||
CLIPBOARD_CLEAR_PRIMARY_CLIP,
|
||||
COMPACT_LAYOUT_TO_LEFT,
|
||||
COMPACT_LAYOUT_TO_RIGHT,
|
||||
UNDO,
|
||||
REDO,
|
||||
VIEW_CHARACTERS,
|
||||
VIEW_SYMBOLS,
|
||||
VIEW_SYMBOLS2,
|
||||
VIEW_NUMERIC_ADVANCED,
|
||||
IME_UI_MODE_TEXT,
|
||||
IME_UI_MODE_MEDIA,
|
||||
IME_UI_MODE_CLIPBOARD,
|
||||
SYSTEM_INPUT_METHOD_PICKER,
|
||||
SYSTEM_PREV_INPUT_METHOD,
|
||||
SYSTEM_NEXT_INPUT_METHOD,
|
||||
IME_SUBTYPE_PICKER,
|
||||
IME_PREV_SUBTYPE,
|
||||
IME_NEXT_SUBTYPE,
|
||||
LANGUAGE_SWITCH,
|
||||
IME_SHOW_UI,
|
||||
IME_HIDE_UI,
|
||||
SETTINGS,
|
||||
INTERNAL_BATCH_EDIT,
|
||||
)
|
||||
}
|
||||
|
||||
/** Predefined key data for [KeyCode.UNSPECIFIED] */
|
||||
val UNSPECIFIED = TextKeyData(
|
||||
type = KeyType.UNSPECIFIED,
|
||||
@@ -375,6 +452,12 @@ class TextKeyData(
|
||||
code = KeyCode.IME_NEXT_SUBTYPE,
|
||||
label = "ime_next_subtype",
|
||||
)
|
||||
/** Predefined key data for [KeyCode.LANGUAGE_SWITCH] */
|
||||
val LANGUAGE_SWITCH = TextKeyData(
|
||||
type = KeyType.SYSTEM_GUI,
|
||||
code = KeyCode.LANGUAGE_SWITCH,
|
||||
label = "language_switch",
|
||||
)
|
||||
|
||||
/** Predefined key data for [KeyCode.IME_SHOW_UI] */
|
||||
val IME_SHOW_UI = TextKeyData(
|
||||
@@ -432,9 +515,7 @@ class AutoTextKeyData(
|
||||
override fun asString(isForDisplay: Boolean): String {
|
||||
return buildString {
|
||||
if (isForDisplay || code == KeyCode.URI_COMPONENT_TLD || code < KeyCode.SPACE) {
|
||||
// Combining Diacritical Marks
|
||||
// See: https://en.wikipedia.org/wiki/Combining_Diacritical_Marks
|
||||
if (code in 0x0300..0x036F && !label.startsWith("◌")) {
|
||||
if (Unicode.isNonSpacingMark(code) && !label.startsWith("◌")) {
|
||||
append("◌")
|
||||
}
|
||||
append(label)
|
||||
|
||||
@@ -20,8 +20,10 @@ import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.view.MotionEvent
|
||||
import android.view.animation.AccelerateInterpolator
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -38,6 +40,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.BiasAlignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
@@ -56,14 +59,13 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.toSize
|
||||
import dev.patrickgold.florisboard.FlorisImeService
|
||||
import dev.patrickgold.florisboard.app.prefs.AppPrefs
|
||||
import dev.patrickgold.florisboard.app.prefs.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.app.ui.components.DisposableLifecycleEffect
|
||||
import dev.patrickgold.florisboard.app.ui.components.safeTimes
|
||||
import dev.patrickgold.florisboard.common.FlorisRect
|
||||
import dev.patrickgold.florisboard.common.Pointer
|
||||
import dev.patrickgold.florisboard.common.PointerMap
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationLandscape
|
||||
import dev.patrickgold.florisboard.common.android.isOrientationPortrait
|
||||
import dev.patrickgold.florisboard.common.observeAsTransformingState
|
||||
import dev.patrickgold.florisboard.common.toIntOffset
|
||||
import dev.patrickgold.florisboard.debug.LogTopic
|
||||
@@ -73,7 +75,6 @@ import dev.patrickgold.florisboard.ime.core.InputKeyEvent
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.keyboard.RenderInfo
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.popup.ExceptionsForKeyCodes
|
||||
import dev.patrickgold.florisboard.ime.popup.PopupUiController
|
||||
import dev.patrickgold.florisboard.ime.popup.rememberPopupUiController
|
||||
@@ -115,12 +116,21 @@ fun TextKeyboardLayout(
|
||||
val configuration = LocalConfiguration.current
|
||||
val glideTypingManager by context.glideTypingManager()
|
||||
|
||||
val keyboard = renderInfo.keyboard
|
||||
val numberRowEnabled by prefs.keyboard.numberRow.observeAsTransformingState { numberRowEnabled ->
|
||||
when (keyboard.mode) {
|
||||
KeyboardMode.CHARACTERS,
|
||||
KeyboardMode.NUMERIC_ADVANCED,
|
||||
KeyboardMode.SYMBOLS,
|
||||
KeyboardMode.SYMBOLS2 -> numberRowEnabled
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
val glideEnabled by prefs.glide.enabled.observeAsState()
|
||||
val glideShowTrail by prefs.glide.showTrail.observeAsState()
|
||||
val glideTrailColor = FlorisImeTheme.style.get(element = FlorisImeUi.GlideTrail)
|
||||
.foreground.solidColor(default = Color.Green)
|
||||
|
||||
val keyboard = renderInfo.keyboard
|
||||
val controller = remember { TextKeyboardLayoutController(context) }.also {
|
||||
it.keyboard = keyboard
|
||||
if (glideEnabled && !isSmartbarKeyboard && !isPreview && keyboard.mode == KeyboardMode.CHARACTERS) {
|
||||
@@ -130,15 +140,32 @@ fun TextKeyboardLayout(
|
||||
}
|
||||
val touchEventChannel = remember { Channel<MotionEvent>(64) }
|
||||
|
||||
fun resetAllKeys() {
|
||||
try {
|
||||
val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_CANCEL, 0f, 0f, 0)
|
||||
controller.onTouchEventInternal(event)
|
||||
controller.popupUiController.hide()
|
||||
event.recycle()
|
||||
} catch (e: Throwable) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
controller.glideTypingDetector.registerListener(controller)
|
||||
controller.glideTypingDetector.registerListener(glideTypingManager)
|
||||
onDispose {
|
||||
controller.glideTypingDetector.unregisterListener(controller)
|
||||
controller.glideTypingDetector.unregisterListener(glideTypingManager)
|
||||
resetAllKeys()
|
||||
}
|
||||
}
|
||||
|
||||
DisposableLifecycleEffect(
|
||||
onResume = { /* Do nothing */ },
|
||||
onPause = { resetAllKeys() },
|
||||
)
|
||||
|
||||
BoxWithConstraints(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
@@ -146,7 +173,8 @@ fun TextKeyboardLayout(
|
||||
if (isSmartbarKeyboard) {
|
||||
FlorisImeSizing.smartbarHeight
|
||||
} else {
|
||||
FlorisImeSizing.keyboardRowBaseHeight * keyboard.rowCount
|
||||
FlorisImeSizing.keyboardRowBaseHeight *
|
||||
keyboard.rowCount.coerceAtLeast(if (numberRowEnabled) 5 else 4)
|
||||
}
|
||||
)
|
||||
.onGloballyPositioned { coords ->
|
||||
@@ -212,7 +240,8 @@ fun TextKeyboardLayout(
|
||||
height = FlorisImeSizing.smartbarHeight.toPx()
|
||||
} else {
|
||||
width = keyboardWidth / 10f
|
||||
height = FlorisImeSizing.keyboardRowBaseHeight.toPx()
|
||||
height = FlorisImeSizing.keyboardRowBaseHeight.toPx() *
|
||||
(if (numberRowEnabled && keyboard.mode != KeyboardMode.CHARACTERS) 1.12f else 1f)
|
||||
}
|
||||
}
|
||||
desiredKey.visibleBounds.applyFrom(desiredKey.touchBounds).deflateBy(keyMarginH, keyMarginV)
|
||||
@@ -257,7 +286,8 @@ fun TextKeyboardLayout(
|
||||
val c = key.computedData.code
|
||||
val t = key.computedData.type
|
||||
val numeric = keyboard.mode == KeyboardMode.NUMERIC ||
|
||||
keyboard.mode == KeyboardMode.NUMERIC_ADVANCED && t == KeyType.NUMERIC
|
||||
keyboard.mode == KeyboardMode.PHONE || keyboard.mode == KeyboardMode.PHONE2 ||
|
||||
keyboard.mode == KeyboardMode.NUMERIC_ADVANCED && t == KeyType.NUMERIC
|
||||
c > KeyCode.SPACE && c != KeyCode.MULTIPLE_CODE_POINTS && c != KeyCode.CJK_SPACE && !numeric
|
||||
} else {
|
||||
true
|
||||
@@ -314,13 +344,29 @@ private fun TextKeyButton(
|
||||
KeyCode.VIEW_NUMERIC_ADVANCED -> 0.55f
|
||||
else -> 1.0f
|
||||
}
|
||||
SnyggSurface(
|
||||
val size = key.visibleBounds.size.toDpSize()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.requiredSize(key.visibleBounds.size.toDpSize())
|
||||
.requiredSize(size)
|
||||
.absoluteOffset { key.visibleBounds.topLeft.toIntOffset() },
|
||||
style = keyStyle,
|
||||
clip = true,
|
||||
) {
|
||||
// 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 && renderInfo.keyboard.mode == KeyboardMode.PHONE
|
||||
key.label?.let { label ->
|
||||
if (key.computedData.code == KeyCode.SPACE) {
|
||||
val prefs by florisPreferenceModel()
|
||||
@@ -332,7 +378,7 @@ private fun TextKeyButton(
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.align(Alignment.Center),
|
||||
.align(if (isTelpadKey) BiasAlignment(-0.5f, 0f) else Alignment.Center),
|
||||
text = label,
|
||||
color = keyStyle.foreground.solidColor(),
|
||||
fontSize = fontSize,
|
||||
@@ -354,10 +400,10 @@ private fun TextKeyButton(
|
||||
val hintFontSize = keyHintStyle.fontSize.spSize() safeTimes fontSizeMultiplier
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(end = (key.visibleBounds.width / 12f).toDp())
|
||||
.wrapContentSize()
|
||||
.align(Alignment.TopEnd)
|
||||
.snyggBackground(keyHintStyle),
|
||||
.align(if (isTelpadKey) BiasAlignment(0.5f, 0f) else Alignment.TopEnd)
|
||||
.snyggBackground(keyHintStyle)
|
||||
.padding(horizontal = (key.visibleBounds.width / 12f).toDp()),
|
||||
text = hintedLabel,
|
||||
color = keyHintStyle.foreground.solidColor(),
|
||||
fontFamily = FontFamily.Monospace,
|
||||
@@ -398,7 +444,7 @@ private class TextKeyboardLayoutController(
|
||||
|
||||
private var initSelectionStart: Int = 0
|
||||
private var initSelectionEnd: Int = 0
|
||||
var isGliding: Boolean = false
|
||||
var isGliding by mutableStateOf(false)
|
||||
|
||||
val glideTypingDetector = GlideTypingGesture.Detector(context)
|
||||
val glideDataForDrawing = mutableStateListOf<Pair<GlideTypingGesture.Detector.Position, Long>>()
|
||||
@@ -782,7 +828,7 @@ private class TextKeyboardLayoutController(
|
||||
inputFeedbackController?.gestureMovingSwipe(TextKeyData.DELETE)
|
||||
}
|
||||
markComposingRegion(null)
|
||||
if (selection.isValid) {
|
||||
if (selection.isValid && event.absUnitCountX <= 0) {
|
||||
selectionSetNWordsLeft(abs(event.absUnitCountX / 2) - 1)
|
||||
}
|
||||
}
|
||||
@@ -810,7 +856,8 @@ private class TextKeyboardLayoutController(
|
||||
return when (event.type) {
|
||||
SwipeGesture.Type.TOUCH_MOVE -> when (event.direction) {
|
||||
SwipeGesture.Direction.LEFT -> {
|
||||
if (prefs.gestures.spaceBarSwipeLeft.get() == SwipeAction.MOVE_CURSOR_LEFT) {
|
||||
val action = prefs.gestures.spaceBarSwipeLeft.get()
|
||||
if (action == SwipeAction.MOVE_CURSOR_LEFT) {
|
||||
abs(event.relUnitCountX).let {
|
||||
val count = if (!pointer.hasTriggeredGestureMove) {
|
||||
it - 1
|
||||
@@ -826,11 +873,14 @@ private class TextKeyboardLayoutController(
|
||||
)
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
action != SwipeAction.NO_ACTION
|
||||
}
|
||||
true
|
||||
}
|
||||
SwipeGesture.Direction.RIGHT -> {
|
||||
if (prefs.gestures.spaceBarSwipeRight.get() == SwipeAction.MOVE_CURSOR_RIGHT) {
|
||||
val action = prefs.gestures.spaceBarSwipeRight.get()
|
||||
if (action == SwipeAction.MOVE_CURSOR_RIGHT) {
|
||||
abs(event.relUnitCountX).let {
|
||||
val count = if (!pointer.hasTriggeredGestureMove) {
|
||||
it - 1
|
||||
@@ -846,29 +896,43 @@ private class TextKeyboardLayoutController(
|
||||
)
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
action != SwipeAction.NO_ACTION
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> true // To prevent the popup display of nearby keys
|
||||
}
|
||||
SwipeGesture.Type.TOUCH_UP -> when (event.direction) {
|
||||
SwipeGesture.Direction.LEFT -> {
|
||||
prefs.gestures.spaceBarSwipeLeft.get().let {
|
||||
if (it != SwipeAction.MOVE_CURSOR_LEFT) {
|
||||
keyboardManager.executeSwipeAction(it)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
when {
|
||||
it == SwipeAction.NO_ACTION -> {
|
||||
false
|
||||
}
|
||||
it != SwipeAction.MOVE_CURSOR_LEFT -> {
|
||||
keyboardManager.executeSwipeAction(it)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SwipeGesture.Direction.RIGHT -> {
|
||||
prefs.gestures.spaceBarSwipeRight.get().let {
|
||||
if (it != SwipeAction.MOVE_CURSOR_RIGHT) {
|
||||
keyboardManager.executeSwipeAction(it)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
when {
|
||||
it == SwipeAction.NO_ACTION -> {
|
||||
false
|
||||
}
|
||||
it != SwipeAction.MOVE_CURSOR_RIGHT -> {
|
||||
keyboardManager.executeSwipeAction(it)
|
||||
true
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -970,21 +1034,3 @@ private class TextKeyboardLayoutController(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppPrefs.Keyboard.fontSizeMultiplier(): Float {
|
||||
val configuration = LocalConfiguration.current
|
||||
val oneHandedMode by oneHandedMode.observeAsState()
|
||||
val oneHandedModeFactor by oneHandedModeScaleFactor.observeAsTransformingState { it / 100.0f }
|
||||
val fontSizeMultiplierBase by if (configuration.isOrientationPortrait()) {
|
||||
fontSizeMultiplierPortrait
|
||||
} else {
|
||||
fontSizeMultiplierLandscape
|
||||
}.observeAsTransformingState { it / 100.0f }
|
||||
val fontSizeMultiplier = fontSizeMultiplierBase * if (oneHandedMode != OneHandedMode.OFF && configuration.isOrientationPortrait()) {
|
||||
oneHandedModeFactor
|
||||
} else {
|
||||
1.0f
|
||||
}
|
||||
return fontSizeMultiplier
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ object FlorisImeUi {
|
||||
const val EmojiKeyPopup = "emoji-key-popup"
|
||||
const val EmojiTab = "emoji-tab"
|
||||
|
||||
const val ExtractedLandscapeInputLayout = "extracted-landscape-input-layout"
|
||||
const val ExtractedLandscapeInputField = "extracted-landscape-input-field"
|
||||
const val ExtractedLandscapeInputAction = "extracted-landscape-input-action"
|
||||
|
||||
const val GlideTrail = "glide-trail"
|
||||
|
||||
const val OneHandedPanel = "one-handed-panel"
|
||||
|
||||
@@ -101,6 +101,7 @@ object FlorisImeUiSpec : SnyggSpec({
|
||||
background()
|
||||
foreground()
|
||||
font()
|
||||
shape()
|
||||
}
|
||||
element(FlorisImeUi.KeyPopup) {
|
||||
background()
|
||||
@@ -204,6 +205,22 @@ object FlorisImeUiSpec : SnyggSpec({
|
||||
foreground()
|
||||
}
|
||||
|
||||
element(FlorisImeUi.ExtractedLandscapeInputLayout) {
|
||||
background()
|
||||
}
|
||||
element(FlorisImeUi.ExtractedLandscapeInputField) {
|
||||
background()
|
||||
foreground()
|
||||
font()
|
||||
shape()
|
||||
border()
|
||||
}
|
||||
element(FlorisImeUi.ExtractedLandscapeInputAction) {
|
||||
background()
|
||||
foreground()
|
||||
shape()
|
||||
}
|
||||
|
||||
element(FlorisImeUi.GlideTrail) {
|
||||
foreground()
|
||||
}
|
||||
|
||||
@@ -16,25 +16,76 @@
|
||||
|
||||
package dev.patrickgold.florisboard.util
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.text.TextUtils
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.view.inputmethod.EditorInfoCompat
|
||||
import dev.patrickgold.florisboard.common.android.AndroidVersion
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private const val SECTION_SEPARATOR = "---"
|
||||
|
||||
fun EditorInfo.debugSummarize(): String {
|
||||
return StringBuilder().let {
|
||||
it.appendLine(this::class.qualifiedName)
|
||||
it.append("imeOptions: ").appendLine(this.imeOptions.debugSummarize(EditorInfo::class))
|
||||
it.append("initialCapsMode: ").appendLine(this.initialCapsMode.debugSummarize(TextUtils::class))
|
||||
it.append("initialSelStart: ").appendLine(this.initialSelStart)
|
||||
it.append("initialSelEnd: ").appendLine(this.initialSelEnd)
|
||||
it.append("inputType: ").appendLine(this.inputType.debugSummarize(InputType::class))
|
||||
it.append("packageName: ").appendLine(this.packageName)
|
||||
it.toString()
|
||||
val info = this
|
||||
return buildString {
|
||||
appendLine(info::class.qualifiedName)
|
||||
append("packageName: ").appendLine(info.packageName)
|
||||
appendLine(SECTION_SEPARATOR)
|
||||
append("inputType: ").appendLine(info.inputType.debugSummarize(InputType::class))
|
||||
append("imeOptions: ").appendLine(info.imeOptions.debugSummarize(EditorInfo::class))
|
||||
append("privateImeOptions: ").appendLine(info.privateImeOptions ?: "(null)")
|
||||
appendLine(SECTION_SEPARATOR)
|
||||
append("actionId: ").appendLine(info.actionId.dsEditorInfoActionId())
|
||||
append("actionLabel: ").appendLine(info.actionLabel ?: "(null)")
|
||||
append("contentMimeTypes: ").appendLine(EditorInfoCompat.getContentMimeTypes(info).contentToString())
|
||||
append("extras: ").appendLine(info.extras?.debugSummarize() ?: "(null)")
|
||||
append("hintLocales: ").also {
|
||||
if (AndroidVersion.ATLEAST_API24_N) {
|
||||
appendLine(info.hintLocales?.toLanguageTags() ?: "(null)")
|
||||
} else {
|
||||
appendLine("(null)")
|
||||
}
|
||||
}
|
||||
append("hintText: ").appendLine(info.hintText ?: "(null)")
|
||||
appendLine(SECTION_SEPARATOR)
|
||||
append("initialCapsMode: ").appendLine(info.initialCapsMode.debugSummarize(TextUtils::class))
|
||||
append("initialSelStart: ").appendLine(info.initialSelStart)
|
||||
append("initialSelEnd: ").appendLine(info.initialSelEnd)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T: Any> Int.debugSummarize(type: KClass<T>): String {
|
||||
private fun Bundle.debugSummarize(): String {
|
||||
val bundle = this
|
||||
return buildString {
|
||||
append("[")
|
||||
for ((i, key) in bundle.keySet().withIndex()) {
|
||||
if (i > 0) {
|
||||
append(",")
|
||||
}
|
||||
append(key)
|
||||
append("=")
|
||||
append(bundle.get(key))
|
||||
}
|
||||
append("]")
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.dsEditorInfoActionId(): String {
|
||||
return when (this) {
|
||||
EditorInfo.IME_ACTION_DONE -> "IME_ACTION_DONE"
|
||||
EditorInfo.IME_ACTION_GO -> "IME_ACTION_GO"
|
||||
EditorInfo.IME_ACTION_NEXT -> "IME_ACTION_NEXT"
|
||||
EditorInfo.IME_ACTION_NONE -> "IME_ACTION_NONE"
|
||||
EditorInfo.IME_ACTION_PREVIOUS -> "IME_ACTION_PREVIOUS"
|
||||
EditorInfo.IME_ACTION_SEARCH -> "IME_ACTION_SEARCH"
|
||||
EditorInfo.IME_ACTION_SEND -> "IME_ACTION_SEND"
|
||||
EditorInfo.IME_ACTION_UNSPECIFIED -> "IME_ACTION_UNSPECIFIED"
|
||||
else -> String.format("0x%08x", this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T: Any> Int.debugSummarize(type: KClass<T>): String {
|
||||
val summary = StringBuilder()
|
||||
when (type) {
|
||||
EditorInfo::class -> {
|
||||
@@ -43,17 +94,7 @@ fun <T: Any> Int.debugSummarize(type: KClass<T>): String {
|
||||
summary.append("IME_NULL")
|
||||
}
|
||||
else -> {
|
||||
val tAction = when (this and EditorInfo.IME_MASK_ACTION) {
|
||||
EditorInfo.IME_ACTION_DONE -> "IME_ACTION_DONE"
|
||||
EditorInfo.IME_ACTION_GO -> "IME_ACTION_GO"
|
||||
EditorInfo.IME_ACTION_NEXT -> "IME_ACTION_NEXT"
|
||||
EditorInfo.IME_ACTION_NONE -> "IME_ACTION_NONE"
|
||||
EditorInfo.IME_ACTION_PREVIOUS -> "IME_ACTION_PREVIOUS"
|
||||
EditorInfo.IME_ACTION_SEARCH -> "IME_ACTION_SEARCH"
|
||||
EditorInfo.IME_ACTION_SEND -> "IME_ACTION_SEND"
|
||||
EditorInfo.IME_ACTION_UNSPECIFIED -> "IME_ACTION_UNSPECIFIED"
|
||||
else -> String.format("0x%08x", this and EditorInfo.IME_MASK_ACTION)
|
||||
}
|
||||
val tAction = (this and EditorInfo.IME_MASK_ACTION).dsEditorInfoActionId()
|
||||
val tFlags = StringBuilder()
|
||||
if (this and EditorInfo.IME_FLAG_FORCE_ASCII > 0) {
|
||||
tFlags.append("IME_FLAG_FORCE_ASCII|")
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle" android:tintMode="multiply">
|
||||
<solid android:color="@android:color/transparent"/>
|
||||
<corners android:radius="@dimen/landscapeInputUi_editText_cornerRadius"/>
|
||||
<stroke android:width="@dimen/landscapeInputUi_editText_borderWidth" android:color="@android:color/white"/>
|
||||
</shape>
|
||||
5
app/src/main/res/drawable/ic_pageview.xml
Normal file
5
app/src/main/res/drawable/ic_pageview.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M11.5,9C10.12,9 9,10.12 9,11.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5S12.88,9 11.5,9zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM16.79,18.21l-2.91,-2.91c-0.69,0.44 -1.51,0.7 -2.39,0.7C9.01,16 7,13.99 7,11.5S9.01,7 11.5,7 16,9.01 16,11.5c0,0.88 -0.26,1.69 -0.7,2.39l2.91,2.9 -1.42,1.42z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_videocam.xml
Normal file
5
app/src/main/res/drawable/ic_videocam.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#000000" android:pathData="M15,8v8H5V8h10m1,-2H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4V7c0,-0.55 -0.45,-1 -1,-1z"/>
|
||||
</vector>
|
||||
@@ -103,16 +103,23 @@
|
||||
<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_codes">رموز المفتاح المستهدف</string>
|
||||
<string name="settings__theme_editor__rule_groups">مجموعات</string>
|
||||
<string name="settings__theme_editor__rule_modes">أنماط</string>
|
||||
<string name="settings__theme_editor__rule_selectors">محددات</string>
|
||||
<string name="settings__theme_editor__add_code">إضافة كود</string>
|
||||
<string name="settings__theme_editor__edit_code">تعديل الكود</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">لم يتم تعريف اي كود.</string>
|
||||
<string name="settings__theme_editor__add_code">إضافة رموز المفتاح</string>
|
||||
<string name="settings__theme_editor__edit_code">تعديل رمز المفتاح</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">تطبيق القاعدة على جميع العناصر المستهدفة.</string>
|
||||
<string name="settings__theme_editor__codes_defined">تطبيق القاعدة فقط على العناصر المستهدفة ذات الرموز الرئيسية التالية:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">تم تعريف رمز المفتاح هذا بالفعل.</string>
|
||||
<string name="settings__theme_editor__code_invalid">رمز المفتاح هذا غير صالح. تأكد من أن رمز المفتاح يقع في نطاق {c_min} إلى {c_max} للأحرف أو {i_min} إلى {i_max} للمفاتيح الخاصة الداخلية.</string>
|
||||
<string name="settings__theme_editor__code_help_text">ستساعدك الروابط التالية في العثور على رمز المفتاح المقابل:</string>
|
||||
<string name="settings__theme_editor__code_help_text">بدلاً من ذلك ، ستساعدك الروابط التالية في العثور على رمز المفتاح المقابل:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">رمز</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">للعثور على رمز المفتاح ، استخدم الزر بجانب حقل إدخال الرمز. بمجرد تنشيطه ، سيتم تسجيل الضغط على المفتاح التالي وسيقوم بإدخال الرمز في حقل الإدخال.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">بدأ تسجيل رمز المفتاح</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">توقف تسجيل رمز المفتاح</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">يجب أن يكون {app_name} هو لوحة المفاتيح الافتراضية لتسجيل رمز المفتاح</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">جارٍ التسجيل…</string>
|
||||
<string name="settings__theme_editor__add_property">إضافة خاصية</string>
|
||||
<string name="settings__theme_editor__edit_property">تحرير خاصية</string>
|
||||
<string name="settings__theme_editor__property_already_exists">توجد خاصية بهذا الاسم بالفعل داخل القاعدة الحالية.</string>
|
||||
|
||||
@@ -49,11 +49,12 @@
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">Клавиатурата FlorisBoard не е активна в системата и не е достъпна като метод за въвеждане. Докоснете тук, за да промените.</string>
|
||||
<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_language_names_in__label" comment="Label of Display language names in 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__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">Променяне на подредба</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Основен език</string>
|
||||
<string name="settings__localization__subtype_popup_mapping" comment="Label for popup mapping dropdown in subtype screen">Подсказки</string>
|
||||
<string name="settings__localization__subtype_characters_layout" comment="Label for layout dropdown in subtype dialog">Подредба на клавишите</string>
|
||||
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">Символи, основен изглед</string>
|
||||
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">Символи, вторичен изглед</string>
|
||||
@@ -102,16 +103,23 @@
|
||||
<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_codes">Целеви кодове</string>
|
||||
<string name="settings__theme_editor__rule_groups">Групи</string>
|
||||
<string name="settings__theme_editor__rule_modes">Режим</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Селектор</string>
|
||||
<string name="settings__theme_editor__add_code">Добавяне на код</string>
|
||||
<string name="settings__theme_editor__edit_code">Промяна на код</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Липсват кодове.</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Правилото се прилага към всички целеви елементи.</string>
|
||||
<string name="settings__theme_editor__codes_defined">Правилото се прилага само към целевите елементи със следните кодове:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Кодът вече е дефиниран.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Кодът не е валиден. Уверете се че стойността му е между {c_min} и {c_max} за букви и между {i_min} и {i_max} за вградените спициални клавиши.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Следните препратки ще са ви от полза при намиране на клавишни кодове:</string>
|
||||
<string name="settings__theme_editor__code_help_text">Следните препратки ще са ви от полза при намиране на кода на клавиш:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Код на клавиш</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">За да намерите кода на даден клавиш използвайте бутона до полето. Веднъж натиснат в полето ще се запише кода на следващия натиснат клавиш.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">Записът на кода на клавиш е започнат</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">Записът на кода на клавиш е спрян</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">За да запише кода на клавиша, {app_name} трябва да е подразбираната клавиатура</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Записване…</string>
|
||||
<string name="settings__theme_editor__add_property">Добавяне на свойство</string>
|
||||
<string name="settings__theme_editor__edit_property">Променяне на свойство</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Свойство с това име вече съществува в текущото правило.</string>
|
||||
@@ -133,6 +141,16 @@
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Подсказка на елемент от междинната памет</string>
|
||||
<string name="snygg__rule_element__glide_trail">Следа от плъзгане</string>
|
||||
<string name="snygg__rule_element__one_handed_panel">Панел за работа с една ръка</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_row">Интелигентна лента, основен ред</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_row">Интелигентна лента, допълнителен ред</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_actions_toggle">Интелигентна лента, бутон за превкл. на основната лента</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_actions_toggle">Интелигентна лента, бутон за превкл. на допълнителната лента</string>
|
||||
<string name="snygg__rule_element__smartbar_quick_action">Интелигентна лента, бързи действия</string>
|
||||
<string name="snygg__rule_element__smartbar_key">Бутон за интелигентната лента</string>
|
||||
<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>
|
||||
@@ -226,7 +244,7 @@
|
||||
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Докосване на клавишите</string>
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">Видима изскачаща подсказка</string>
|
||||
<string name="pref__keyboard__popup_enabled__summary" comment="Preference summary">Показва се изскачаща подсказка при докосване на клавиш</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__label" comment="Preference title">Акцентите в посдказките</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__label" comment="Preference title">Акцентите в подсказките</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__summary" comment="Preference summary">Добавят се подсказки със символи към подразбираната подредба</string>
|
||||
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Закъснение при задържане на клавиш</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Клавишът интервал превключва към букви</string>
|
||||
@@ -237,6 +255,7 @@
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Показва се над първия ред</string>
|
||||
<string name="pref__smartbar__flip_toggles__label" comment="Preference title">Разменяне на превключващите бутони</string>
|
||||
<string name="pref__smartbar__flip_toggles__summary" comment="Preference summary">Разменят се бутоните, превключващи редовете</string>
|
||||
<string name="pref__smartbar__any_row_type__label" comment="Preference title">Съдържание на реда</string>
|
||||
<string name="pref__smartbar__group_primary_actions__label" comment="Preference group title">Основни действия</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__label" comment="Preference title">Автоматично разтваряне/събиране</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__summary" comment="Preference summary">Автоматично се разтваря/събира основния ред, на базата на състоянието</string>
|
||||
@@ -247,10 +266,10 @@
|
||||
<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__suggestion__clipboard_content_timeout__label" comment="Preference title">Времеви прозорец за предложения от междинната памет</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__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>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Автоматично въвеждане на главни букви</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Използват се главни букви въз основа на контекста на въвеждане</string>
|
||||
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">Запомняне на състоянието на клавиш Caps Lock</string>
|
||||
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Клавишът Caps Lock се оставя включен при преместване в друго текстово поле</string>
|
||||
<string name="pref__correction__double_space_period__label" comment="Preference title">Точка при двоен интервал</string>
|
||||
@@ -510,13 +529,19 @@
|
||||
<string name="ext__editor__title_edit_theme">Промяна на добавка с тема</string>
|
||||
<string name="ext__editor__metadata__title">Управление на мета данни</string>
|
||||
<string name="ext__editor__metadata__title_invalid">Недействителни мета данни</string>
|
||||
<string name="ext__editor__metadata__message_invalid">Описателните данни на резширението са недействителни. Проверете редактора за описателни данни за подробности!</string>
|
||||
<string name="ext__editor__dependencies__title">Управление на зависимости</string>
|
||||
<string name="ext__editor__files__title">Управление на архиви</string>
|
||||
<string name="ext__editor__create_component__title">Създаване на компонент</string>
|
||||
<string name="ext__editor__create_component__title_theme">Създаване на тема</string>
|
||||
<string name="ext__editor__create_component__from_empty">Празна</string>
|
||||
<string name="ext__editor__create_component__from_existing">От съществуваща</string>
|
||||
<string name="ext__editor__edit_component__title">Редактиране на компонент</string>
|
||||
<string name="ext__editor__edit_component__title_theme">Редактиране на компонент-тема</string>
|
||||
<string name="ext__export__success">Темата е изнесена успешно!</string>
|
||||
<string name="ext__export__failure">Грешка при изнасяне на разширение: {error_message}</string>
|
||||
<string name="ext__import__success">Темата е внесена успешно!</string>
|
||||
<string name="ext__import__failure">Грешка при внасяне на разширение: {error_message}</string>
|
||||
<string name="ext__import__ext_any" comment="Title of Importer screen for import of any supported FlorisBoard extension">Внасяне на добавка</string>
|
||||
<string name="ext__import__ext_keyboard" comment="Title of Importer screen for keyboard extension import">Внасяне на добавка с клавиатура</string>
|
||||
<string name="ext__import__ext_spelling" comment="Title of Importer screen for spelling extension (or raw dictionary) import">Внасяне на добавка за правопис / речник</string>
|
||||
@@ -584,8 +609,8 @@
|
||||
<string name="enum__display_kbd_after_dialogs__never__description" comment="Enum value description">Клавиатурата не се показва никога след затваряне на диалог</string>
|
||||
<string name="enum__display_kbd_after_dialogs__remember" comment="Enum value label">Запомняне на последното състояние</string>
|
||||
<string name="enum__display_kbd_after_dialogs__remember__description" comment="Enum value description">Клавиатурата се показва след затваряне на диалог ако преди това е видима</string>
|
||||
<string name="enum__display_language_names_in__system_locale" comment="Enum value label">Език на системата</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">Присъщ за езика</string>
|
||||
<string name="enum__display_language_names_in__system_locale" comment="Enum value label">Езика на системата</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">Присъщия за езика</string>
|
||||
<string name="enum__emoji_skin_tone__default" comment="Enum value label">{emoji} Подразбиран цвят на кожата</string>
|
||||
<string name="enum__emoji_skin_tone__light_skin_tone" comment="Enum value label">{emoji} Светъл цвят на кожа</string>
|
||||
<string name="enum__emoji_skin_tone__medium_light_skin_tone" comment="Enum value label">{emoji} Средно светъл цвят на кожата</string>
|
||||
@@ -617,12 +642,15 @@
|
||||
<string name="enum__secondary_row_placement__below_primary" comment="Enum value label">Под първия ред</string>
|
||||
<string name="enum__secondary_row_placement__below_primary__description" comment="Enum value description">Добавя се втори ред между първия ред и клавиатурата</string>
|
||||
<string name="enum__secondary_row_placement__overlay_app_ui" comment="Enum value label">Слой върху приложението</string>
|
||||
<string name="enum__secondary_row_placement__overlay_app_ui__description" comment="Enum value description">Добавя се втори ред като плаващ слой над клавиатурата без да се увеличава височината ѝ. Имайте предвид, че по този начин полето за въвеждане може частично да бъде закрито</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Горе, начало</string>
|
||||
<string name="enum__shape_corner__top_end" comment="Enum value label">Горе, край</string>
|
||||
<string name="enum__shape_corner__bottom_end" comment="Enum value label">Долу, край</string>
|
||||
<string name="enum__shape_corner__bottom_start" comment="Enum value label">Долу, начало</string>
|
||||
<string name="enum__smartbar_row_type__quick_actions" comment="Enum value label">Бързи действия</string>
|
||||
<string name="enum__smartbar_row_type__clipboard_cursor_tools" comment="Enum value label">Инструменти за междинна памет и каретка</string>
|
||||
<string name="enum__smartbar_row_type__quick_actions__description" comment="Enum value description">Бързите действия, подредени в един ред с допълнително меню</string>
|
||||
<string name="enum__smartbar_row_type__clipboard_cursor_tools" comment="Enum value label">Инструменти за междинната памет и каретката</string>
|
||||
<string name="enum__smartbar_row_type__clipboard_cursor_tools__description" comment="Enum value description">Най-използваните действия с междинната памет и придвижване на каретката</string>
|
||||
<string name="enum__snygg_level__basic" comment="Enum value label">Основен</string>
|
||||
<string name="enum__snygg_level__basic__description" comment="Enum value description">Само цветове, свойствата и правилата са преведени.</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Разширен</string>
|
||||
|
||||
@@ -88,13 +88,9 @@
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Gestiona els temes instal·lats</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_codes">Codis</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grups</string>
|
||||
<string name="settings__theme_editor__rule_modes">Modes</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selectors</string>
|
||||
<string name="settings__theme_editor__add_code">Afegir codi</string>
|
||||
<string name="settings__theme_editor__edit_code">Editar el codi</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Cap codi definit.</string>
|
||||
<string name="settings__theme_editor__add_property">Afegir propietat</string>
|
||||
<string name="settings__theme_editor__edit_property">Editar propietat</string>
|
||||
<string name="settings__theme_editor__property_name">Nom de la propietat</string>
|
||||
|
||||
@@ -103,16 +103,23 @@
|
||||
<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_codes">سەرچاوەی کۆدی مەبەست</string>
|
||||
<string name="settings__theme_editor__rule_groups">گرووپ</string>
|
||||
<string name="settings__theme_editor__rule_modes">شێواز</string>
|
||||
<string name="settings__theme_editor__rule_selectors">هەڵبژاردن</string>
|
||||
<string name="settings__theme_editor__add_code">زیادکردنی کۆد</string>
|
||||
<string name="settings__theme_editor__add_code">زیادکردنی کۆدی دوگمە</string>
|
||||
<string name="settings__theme_editor__edit_code">دەستکاریکردنی کۆد</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">کۆد نەنوسراوە</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">جێبەجێکردن بۆ سەرجەم بەشەکان</string>
|
||||
<string name="settings__theme_editor__codes_defined">جێبەجێ کردنی یاسا تەنها بۆ ئامانج توخمەکان لەگەڵ کۆدەکانی کلیلی خوارەوە:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">ئەم دوگمەیە پێشتر زیادکراوە</string>
|
||||
<string name="settings__theme_editor__code_invalid">ئەم کۆدە کلیلە دروست نیە، دڵنیابە لەوەی کە کۆدی کلیلەکە لەناو مەودای {c_min} بۆ {c_max} بۆ پیتەکان یان {i_min} بۆ {i_max} بۆ کلیلە تایبەتەکان.</string>
|
||||
<string name="settings__theme_editor__code_help_text">ئەم لینکانەی خوارەوە یارمەتیت دەدەن بۆ دۆزینەوەی کۆدی کلیلی هاوتا:</string>
|
||||
<string name="settings__theme_editor__code_help_text">ئەم لینکانەی خوارەوە یارمەتیت ئەدەن بۆ دۆزینەوەی کۆدی کلیلی هاوتا:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">کۆد</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">بۆ دۆزینەوەی کۆدی کلیلێک، دوگمەکە بەکاربهێنە جگە لە خانەی نوسینی کۆدەکە، کاتێک چالاک کرا، کلیلەکانی دواتر تۆمار دەکات و کۆدەکە دادەنێت بۆ خانەکە.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">دۆزینەوەی کۆد دەستیپێکرد</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">دۆزینەوەی کۆد وەستێنرا</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} پێویستە کرابێتە تەختەکلیلی بنەڕەتی بۆ ئەوەی بتوانی کۆدەکە بدۆیتەوە</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">دۆزینەوە…</string>
|
||||
<string name="settings__theme_editor__add_property">زیادکردنی بەش</string>
|
||||
<string name="settings__theme_editor__edit_property">دەستکاریکردنی بەش</string>
|
||||
<string name="settings__theme_editor__property_already_exists">تایبەتمەندیەک بەم ناوە پێشتر لەناو ئەم یاسایەدا هەیە.</string>
|
||||
@@ -128,7 +135,7 @@
|
||||
<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__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>
|
||||
@@ -713,7 +720,7 @@
|
||||
<!-- Unit strings (symbols) -->
|
||||
<!-- Unit strings (written words) -->
|
||||
<plurals name="unit__hours__written">
|
||||
<item quantity="one">{v} هاتژمێر</item>
|
||||
<item quantity="one">{v} کاتژمێر</item>
|
||||
<item quantity="other">{v} کاتژمێر</item>
|
||||
</plurals>
|
||||
<plurals name="unit__minutes__written">
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emoji</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emotikony</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Maximální velikost historie emotikonů</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Preferovaná barva pokožky emotikonů</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Preferovaný styl vlasů emotikonů</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smajlíky & Emoce</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Lidé & Tělo</string>
|
||||
@@ -23,6 +26,9 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Předměty</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symboly</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Vlajky</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Nenalezeny žádné nedávno použité emotikony. Jakmile je začnete psát, objeví se automaticky zde.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Tip: Stiskněte a držte prst na naposledy použitých emotikonech pro jejich odebrání z daného seznamu!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Emotikon {emoji} byl odebrán z nedávno použitých</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="smartbar__quick_action_toggle__alt" comment="Content description for the quick action toggle button in Smartbar">Přepínač rychlé akce. Pokud ho podržíte, přepne mezi návrhy na slova a tlačítky rychlé akce.</string>
|
||||
<string name="smartbar__quick_action__exit_editing" comment="Content-description for the exit editing layout button in Smartbar">Opustit editor textu.</string>
|
||||
@@ -43,13 +49,16 @@
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">FlorisBord není povolena v systému a proto nemůže být použita jako metoda zadávání. Klikněte sem pro vyřešení tohoto problému.</string>
|
||||
<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__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__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">Upravit podtyp</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Hlavní jazyk</string>
|
||||
<string name="settings__localization__subtype_popup_mapping" comment="Label for popup mapping dropdown in subtype screen">Mapování vyskakovacích nabídek</string>
|
||||
<string name="settings__localization__subtype_characters_layout" comment="Label for layout dropdown in subtype dialog">Rozložení znaků</string>
|
||||
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">Primární rozložení symbolů</string>
|
||||
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">Sekundární rozložení symbolů</string>
|
||||
<string name="settings__localization__subtype_composer" comment="Label for composer dropdown in subtype dialog.">Skládání</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).">List měn</string>
|
||||
<string name="settings__localization__subtype_numeric_layout" comment="Label for layout dropdown in subtype dialog">Číselné rozložení</string>
|
||||
<string name="settings__localization__subtype_numeric_advanced_layout" comment="Label for layout dropdown in subtype dialog">Číselné rozložení (pokročilé)</string>
|
||||
@@ -66,6 +75,7 @@
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">Zobrazit všechny</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">Zdá se, že jste nenakonfigurovali žádné podtypy. Jako fallback bude použit podtyp angličtina/QWERTY!</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Tento podtyp již existuje!</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)">Minimálně jedno pole nemá vybranou hodnotu. Vyberte ji prosím.</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} (nenainstalováno)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Rozložení</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Motiv</string>
|
||||
@@ -83,16 +93,16 @@
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">Vyberte denní motiv</string>
|
||||
<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_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">Spravovat nainstalované motivy</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__rule_element">Cílový prvek</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kódy</string>
|
||||
<string name="settings__theme_editor__rule_groups">Skupiny</string>
|
||||
<string name="settings__theme_editor__rule_modes">Režimy</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selektory</string>
|
||||
<string name="settings__theme_editor__add_code">Přidat kód</string>
|
||||
<string name="settings__theme_editor__edit_code">Upravit kód</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Nejsou definovány žádné kódy.</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Tento klávesový kód je již definován.</string>
|
||||
<string name="settings__theme_editor__add_property">Přidat vlastnost</string>
|
||||
<string name="settings__theme_editor__edit_property">Upravit vlastnost</string>
|
||||
@@ -100,6 +110,7 @@
|
||||
<string name="settings__theme_editor__property_name">Název vlastnosti</string>
|
||||
<string name="settings__theme_editor__property_value">Hodnota vlastnosti</string>
|
||||
<string name="settings__theme_editor__property_value_shape_apply_for_all_corners">Použít pro všechny rohy</string>
|
||||
<string name="settings__theme_editor__property_value_color_dialog_title">Upravit řetězec barvy</string>
|
||||
<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="snygg__rule_element__defines">Proměnné</string>
|
||||
@@ -107,25 +118,80 @@
|
||||
<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__glide_trail">Stopa tahu</string>
|
||||
<string name="snygg__rule_element__one_handed_panel">Režim jedné ruky</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_row">Primární řádek chytré lišty</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_row">Sekundární řádek chytré lišty</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_actions_toggle">Primární přepínač akcí chytré lišty</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_actions_toggle">Sekundární přepínač akcí rychlé lišty</string>
|
||||
<string name="snygg__rule_element__smartbar_quick_action">Rychlá akce chytré lišty</string>
|
||||
<string name="snygg__rule_element__smartbar_key">Klíč chytré lišty</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Navrhnuté slovo v chytré liště</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Navrhnutý klip 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>
|
||||
<string name="snygg__property_name__border_style">Styl okraje</string>
|
||||
<string name="snygg__property_name__border_width">Šířka okraje</string>
|
||||
<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="pref__input_feedback__group_haptic__label" comment="Preference group title">Hmatová odezva / vibrace</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__label" comment="Preference title">Povolit hmatovou odezvu</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__summary" comment="Preference summary">Vibrovat při vstupních událostech, záleží na nastavení systému</string>
|
||||
<string name="pref__input_feedback__haptic_ignore_system_settings__label" comment="Preference title">Ignorovat hmatová nastavení systému</string>
|
||||
<string name="pref__input_feedback__haptic_ignore_system_settings__summary" comment="Preference summary">Použít předvolby níže, i při vypnutých vybracích v systému</string>
|
||||
<string name="pref__input_feedback__haptic_use_vibrator__label" comment="Preference title">Přímé spuštění vibrací</string>
|
||||
<string name="pref__input_feedback__haptic_use_vibrator__summary" comment="Preference summary">Spustit vibrace přímo namísto použití sady pro hmatovou odezvu systému Android</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">Trvání vibrací</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">Síla vibrací</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_press__label" comment="Preference title">Vibrace při stisku klávesy</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_long_press__label" comment="Preference title">Vibrace při dlouhém stisku klávesy</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_repeated_action__label" comment="Preference title">Vibrace při opakované akci klávesy</string>
|
||||
<string name="pref__input_feedback__haptic_feat_gesture_swipe__label" comment="Preference title">Vibrace při gestech</string>
|
||||
<string name="pref__input_feedback__haptic_feat_gesture_moving_swipe__label" comment="Preference title">Vibrace při posouvání prstem při gestech</string>
|
||||
<string name="pref__input_feedback__any_feat_key_press__summary" comment="Preference summary">např. klávesy, tlačítka, záložky emotikonů</string>
|
||||
<string name="pref__input_feedback__any_feat_key_long_press__summary" comment="Preference summary">např. vyskakovací nabídky</string>
|
||||
<string name="pref__input_feedback__any_feat_key_repeated_action__summary" comment="Preference summary">např. klávesa odstranění</string>
|
||||
<string name="pref__input_feedback__any_feat_gesture_swipe__summary" comment="Preference summary">není implementováno</string>
|
||||
<string name="pref__input_feedback__any_feat_gesture_moving_swipe__summary" comment="Preference summary">např. posunutí při ovládání kurzoru</string>
|
||||
<string name="settings__keyboard__title" comment="Title of Keyboard preferences screen">Klávesnice</string>
|
||||
<string name="pref__keyboard__number_row__label" comment="Preference title">Řádek čísel</string>
|
||||
<string name="pref__keyboard__number_row__summary" comment="Preference summary">Zobrazit číselný řádek nad znakovým rozložením</string>
|
||||
<string name="pref__keyboard__hinted_number_row_mode__label" comment="Preference title">Řádek čísel s návrhy</string>
|
||||
<string name="pref__keyboard__hinted_symbols_mode__label" comment="Preference title">Navrhované symboly</string>
|
||||
<string name="pref__keyboard__utility_key_enabled__label" comment="Preference title">Zobrazit pomocné tlačítko</string>
|
||||
<string name="pref__keyboard__utility_key_enabled__summary" comment="Preference summary">Zobrazí nastavitelné pomocné tlačítko vedle mezerníku</string>
|
||||
<string name="pref__keyboard__utility_key_action__label" comment="Preference title">Funkce pomocného tlačítka</string>
|
||||
<string name="pref__keyboard__space_bar_language_display_enabled__label" comment="Preference title">Zobrazit jazyk na mezerníku</string>
|
||||
<string name="pref__keyboard__space_bar_language_display_enabled__summary" comment="Preference summary">Zobrazí název aktuálně používaného jazyka na mezerníku</string>
|
||||
<string name="pref__keyboard__font_size_multiplier__label" comment="Preference title">Násobitel velikosti písma</string>
|
||||
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Rozložení</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Režim jedné ruky</string>
|
||||
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Šířka klávesnice v režimu jedné ruky</string>
|
||||
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Vstupní okno v celoobrazovkovém režimu na šířku</string>
|
||||
<string name="pref__keyboard__height_factor__label" comment="Preference title">Výška klávesnice</string>
|
||||
<string name="pref__keyboard__key_spacing__label" comment="Preference title">Mezery mezi klávesami</string>
|
||||
<string name="pref__keyboard__bottom_offset__label" comment="Preference title">Spodní odsazení</string>
|
||||
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Stisk klávesy</string>
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">Viditelnost vyskakovacího okna</string>
|
||||
<string name="pref__keyboard__popup_enabled__summary" comment="Preference summary">Zobrazit vyskakovací okno při stisku klávesy</string>
|
||||
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Délka dlouhého stisku</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="settings__smartbar__title" comment="Title of Smartbar screen">Chytrá lišta</string>
|
||||
<string name="pref__smartbar__enabled__label" comment="Preference title">Povolit chytrou lištu</string>
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Zobrazí se v horní části klávesnice</string>
|
||||
<string name="pref__smartbar__flip_toggles__label" comment="Preference title">Přehodit přepínací tlačítka</string>
|
||||
<!-- Typing strings -->
|
||||
<string name="pref__suggestion__title" comment="Preference group title">Návrhy</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Návrhy obsahu schránky</string>
|
||||
|
||||
@@ -103,16 +103,18 @@
|
||||
<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">Codes</string>
|
||||
<string name="settings__theme_editor__rule_groups">Gruppen</string>
|
||||
<string name="settings__theme_editor__rule_modes">Modi</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selektoren</string>
|
||||
<string name="settings__theme_editor__add_code">Code hinzufügen</string>
|
||||
<string name="settings__theme_editor__edit_code">Code bearbeiten</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Keine Codes definiert.</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Regel auf alle Zielelemente anwenden.</string>
|
||||
<string name="settings__theme_editor__codes_defined">Regel nur auf Zielelemente mit folgenden Codes anwenden:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Dieser Tastencode ist bereits definiert.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Dieser Tastencode ist nicht gültig. Stelle sicher, dass der Tastencode innerhalb der Spanne von {c_min} bis {c_max} für Zeichen oder von {i_min} bis {i_max} für interne Spezialschlüssel liegt.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Die folgenden Links helfen dir, den entsprechenden Tastencode zu finden:</string>
|
||||
<string name="settings__theme_editor__code_help_text">Alternativ werden die folgenden Links helfen die korrespondierenden Codes zu finden:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Code</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">Um den Code einer Taste zu ermitteln, verwenden Sie die Schaltfläche neben dem Code-Eingabefeld. Sobald sie aktiviert ist, zeichnet sie den nächsten Tastendruck auf und fügt den Code in das Eingabefeld ein.</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} muss die standard Tastatur-App sein, um eine Taste aufzunehmen</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Aufnahme läuft…</string>
|
||||
<string name="settings__theme_editor__add_property">Eigenschaft hinzufügen</string>
|
||||
<string name="settings__theme_editor__edit_property">Eigenschaft bearbeiten</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Eine Eigenschaft mit diesem Namen existiert bereits in der aktuellen Regel.</string>
|
||||
@@ -136,6 +138,8 @@
|
||||
<string name="snygg__rule_element__one_handed_panel">Einhändiges Feld</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_row">Smartbar Primärleiste</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_row">Smartbar Sekundärleiste</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_actions_toggle">Smartbar primäre Aktionszeile Schalter</string>
|
||||
<string name="snygg__rule_element__smartbar_quick_action">Smartbar Schnellzugriff</string>
|
||||
<string name="snygg__rule_element__smartbar_key">Smartbartaste</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Smartbar Wortkandidat</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Smartbar Kandidatenclip</string>
|
||||
@@ -240,14 +244,22 @@
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">Pop-Up Sichtbarkeit</string>
|
||||
<string name="pref__keyboard__popup_enabled__summary" comment="Preference summary">Pop-Up bei Tastendruck anzeigen</string>
|
||||
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Verzögerung bei langem Tastendruck</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Leertaste wechselt zu Buchstaben zurück</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Leertaste wechselt aus der Symbol- oder Zahlenansicht zurück zur Buchstabenansicht</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="settings__smartbar__title" comment="Title of Smartbar screen">Schnellzugriffsleiste</string>
|
||||
<string name="pref__smartbar__enabled__label" comment="Preference title">Schnellzugriffsleiste einschalten</string>
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Wird über der Tastatur angezeigt</string>
|
||||
<string name="pref__smartbar__flip_toggles__label" comment="Preference title">Tausche Schalter für Zugriffsleisten</string>
|
||||
<string name="pref__smartbar__any_row_type__label" comment="Preference title">Reihenlayout</string>
|
||||
<string name="pref__smartbar__group_primary_actions__label" comment="Preference group title">Primäre Aktion</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__label" comment="Preference title">Automatisch aus-/einklappen</string>
|
||||
<string name="pref__smartbar__group_secondary_actions__label" comment="Preference group title">Sekundäre Aktionen</string>
|
||||
<string name="pref__smartbar__secondary_actions_enabled__label" comment="Preference title">Zweite Navigationsleiste anzeigen</string>
|
||||
<!-- Typing strings -->
|
||||
<string name="settings__typing__title" comment="Title of Typing experience screen">Vorschläge & Korrekturen</string>
|
||||
<string name="pref__suggestion__title" comment="Preference group title">Vorschläge</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">Zeige Inline-Vorschläge von Autofill-Diensten</string>
|
||||
<string name="pref__suggestion__display_mode__label" comment="Preference title">Darstellungsart für Vorschläge</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Inhalt der Zwischenablage</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title">Timeout für Vorschläge aus der Zwischenablage</string>
|
||||
@@ -647,6 +659,7 @@
|
||||
<string name="enum__shape_corner__top_end" comment="Enum value label">Ende oben</string>
|
||||
<string name="enum__shape_corner__bottom_end" comment="Enum value label">Ende unten</string>
|
||||
<string name="enum__shape_corner__bottom_start" comment="Enum value label">Anfang unten</string>
|
||||
<string name="enum__smartbar_row_type__quick_actions" comment="Enum value label">Schnellzugriffe</string>
|
||||
<string name="enum__snygg_level__basic" comment="Enum value label">Einfach</string>
|
||||
<string name="enum__snygg_level__basic__description" comment="Enum value description">Nur Farbeigenschaften werden angezeigt. Eigenschaften und Regeln werden übersetzt.</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Erweitert</string>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Símbolos</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Banderas</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">No se han encontrado emojis que se hayan usado recientemente. Una vez empieces a usar emojis, aparecerán automáticamente aquí.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Consejo: ¡Pulse sostenidamente los emojis usados recientemente para poder removerlos de esta vista!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Se ha removido {emoji} de los emojis recientes</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="smartbar__quick_action_toggle__alt" comment="Content description for the quick action toggle button in Smartbar">Cambio de acción rápida. Si se pulsa, cambia entre las sugerencias de palabras y los botones de acción rápida.</string>
|
||||
@@ -99,14 +100,22 @@
|
||||
<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</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_modes">Modos</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selectores</string>
|
||||
<string name="settings__theme_editor__add_code">Añadir código</string>
|
||||
<string name="settings__theme_editor__edit_code">Editar código</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">No hay códigos definidos.</string>
|
||||
<string name="settings__theme_editor__add_code">Añadir código clave</string>
|
||||
<string name="settings__theme_editor__edit_code">Editar código clave</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Aplicar la regla a todos los elementos de destino.</string>
|
||||
<string name="settings__theme_editor__codes_defined">Aplicar regla solo para desviar los elementos con los siguientes códigos clave:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Este código clave ya está definido.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Este código clave no es válido. Asegúrese de que el código clave esté dentro del rango de {c_min} a {c_max} para los caracteres o {i_min} a {i_max} para las teclas especiales internas.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Alternativamente, los siguientes enlaces lo ayudarán a encontrar el código clave correspondiente:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Código</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Grabando…</string>
|
||||
<string name="settings__theme_editor__add_property">Añadir propiedad</string>
|
||||
<string name="settings__theme_editor__edit_property">Editar propiedad</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Ya existe una propiedad con este nombre dentro de la regla actual.</string>
|
||||
@@ -128,6 +137,8 @@
|
||||
<string name="snygg__rule_element__one_handed_panel">Panel a una mano</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_row">Fila principal de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_row">Fila secundaria de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_actions_toggle">Acciones primarias de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_actions_toggle">Acciones secundarias de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_quick_action">Barra inteligente de acciones rápidas</string>
|
||||
<string name="snygg__rule_element__smartbar_key">Tecla de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Palabra candidata de barra inteligente</string>
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
<string name="one_handed__move_start_btn_content_description" comment="Content description for the one-handed move to left button">جابهجایی صفحه کلید به سمت چپ.</string>
|
||||
<string name="one_handed__move_end_btn_content_description" comment="Content description for the one-handed move to right button">جابهجایی صفحه کلید به سمت راست.</string>
|
||||
<!-- Media strings -->
|
||||
<string name="settings__media__title">ایموجی ها</string>
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">شکلکها</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticons</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">حداکثر حجم تاریخچه ایموجی</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">رنگ پوست پیشفرض برای ایموجی</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">مدل مو پیشفرض برای ایموجی</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">لبخندی & احساسات</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">مردم & بدن</string>
|
||||
@@ -22,6 +26,9 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">اشیاء</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">نمادها</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">پرچم ها</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">ایموجی استفاده شده ای یافت نشد. زمانی که شروع به نوشتن ایموجی ها بکنید به صورت خودکار اینجا ظاهر خواهند شد.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">توصیه کاربردی: روی ایموجی های استفاده شده نگهدارید تا آن ها را از اینجا حذف کنید!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">ایموجی {emoji} از ایموجی های اخیرا استفاده شده حذف شد</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="smartbar__quick_action_toggle__alt" comment="Content description for the quick action toggle button in Smartbar">ضامن اقدام سریع. در صورت فشار ، بین پیشنهادات کلمه و دکمه های اقدام سریع جابجا می شود.</string>
|
||||
<string name="smartbar__quick_action__exit_editing" comment="Content-description for the exit editing layout button in Smartbar">خروج از صفحه ویرایش متن.</string>
|
||||
@@ -34,6 +41,7 @@
|
||||
<string name="smartbar__quick_action__private_mode" comment="Content-description for the private mode button in Smartbar">در ضورت قابل مشاهده بودن، نشان میـدهد که حالت خصوصی فعال است. در صورت ضربه روی ان، اطلاعاتی درباره حالت خصوصی نشان میدهد.</string>
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">تنظیمات</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">کیبوردتان را امتحان کنید</string>
|
||||
<string name="settings__help" comment="General label for help buttons in Settings">راهنمایی</string>
|
||||
<string name="settings__default" comment="General string which is used when a preference has the default value set">پیشفرض</string>
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">پیشفرض سیستم</string>
|
||||
@@ -41,10 +49,12 @@
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">فلوریس بورد در سیستم به عنوان روش ورودی فعلا نیست و به این علت به عنوان روش ورودی قابل انتخاب نیست. برای حل این مشکل اینجا کلیک کنید.</string>
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">فلوریس بود به عنوان روش ورودی پیش فرض انتخاب نشده. برای حل این مشکل اینجا کلیک کنید.</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__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__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">ویرایش زیر-نوعی</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">زبان اصلی</string>
|
||||
<string name="settings__localization__subtype_popup_mapping" comment="Label for popup mapping dropdown in subtype screen">چینش پاپ آپ ها</string>
|
||||
<string name="settings__localization__subtype_characters_layout" comment="Label for layout dropdown in subtype dialog">چیدمان کاراکتر ها</string>
|
||||
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">چیدمان اصلی نشانه ها</string>
|
||||
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">چیدمان فرعی نشانه ها</string>
|
||||
@@ -63,6 +73,7 @@
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">نمایش همه</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">به نظر میرسد که هیچگونه زیرگروه دیگری را انتخاب نکرده اید. به همین علت زیرگروه English/QWERTY استفاده خواهد شد!</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">این زیرنوع درحال حاضر وجود دارد!</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)">حداقل یکی از فیلد ها خالی است. لطفا یک گزینه برای فیلد(ها) انتخاب کنید.</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} (نصب نشده)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">چیدمان ها</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">تم</string>
|
||||
@@ -77,6 +88,40 @@
|
||||
<string name="pref__theme__source_assets" comment="Label for the theme source field">ابزار های برنامه فلوریس بورد</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">حافظه داخلی</string>
|
||||
<string name="pref__theme__source_external" comment="Label for the theme source field">ارائه دهنده خارجی</string>
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">انتخاب تم روز</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">انتخاب تم شب</string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">مدیریت تم های نصب شده</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_modes">حالت ها</string>
|
||||
<string name="settings__theme_editor__rule_selectors">انتخابگرها</string>
|
||||
<string name="settings__theme_editor__add_code">افزودن کد کلید</string>
|
||||
<string name="settings__theme_editor__edit_code">ویرایش کد کلید</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">قانون را برای تمام مؤلفه ها اعمال کن.</string>
|
||||
<string name="settings__theme_editor__codes_defined">قانون را فقط برای مؤلفه های همراه با این کد کلیدها اعمال کن:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">این کد کلید از قبل تعریف شده است.</string>
|
||||
<string name="settings__theme_editor__code_invalid">این کد کلید صحیح نیست. مطمئن شوید که کد کلید برای کاراکتر ها بین {c_min} تا {c_max} یا برای کلیدهای ویژه داخلی بین {i_min} تا {i_max} هست.</string>
|
||||
<string name="settings__theme_editor__code_help_text">در ضمن لینک های زیر به شما برای یافتن کد کلید متناظر کمک خواهند کرد:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">کد</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">برای یافتن کد یک کلید، از دکمه کنار فیلد ورودی کد استفاده کنید. وقتی که فعال شود، کلید فعال شده بعدی را ضبط کرده و کد آن را وارد فیلد ورودی می کند.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">ضبط کد کلید شروع شد</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">ضبط کد کلید پایان یافت</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} باید به عنوان کیبورد پیشفرض انتخاب شود تا کد کلید را بتوان ضبط کرد</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">در حال ضبط...</string>
|
||||
<string name="settings__theme_editor__add_property">افزودن ویژگی</string>
|
||||
<string name="settings__theme_editor__edit_property">ویرایش ویژگی</string>
|
||||
<string name="settings__theme_editor__property_already_exists">یک ویزگی با همین نام در این قانون از قبل وجود دارد.</string>
|
||||
<string name="settings__theme_editor__property_name">نام ویژگی</string>
|
||||
<string name="settings__theme_editor__property_value">مقدار ویژگی</string>
|
||||
<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__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>
|
||||
|
||||
@@ -103,16 +103,23 @@
|
||||
<string name="settings__theme_editor__no_rules_defined">Cette feuille de style n\'a pas de règles définies. Ajoutez une règle pour commencer à personnaliser cette feuille de style.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Cette règle de feuille de style est déjà définie.</string>
|
||||
<string name="settings__theme_editor__rule_element">Élément cible</string>
|
||||
<string name="settings__theme_editor__rule_codes">Codes</string>
|
||||
<string name="settings__theme_editor__rule_codes">Codes clés de la cible</string>
|
||||
<string name="settings__theme_editor__rule_groups">Groupes</string>
|
||||
<string name="settings__theme_editor__rule_modes">Modes</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Sélecteurs</string>
|
||||
<string name="settings__theme_editor__add_code">Ajouter du code</string>
|
||||
<string name="settings__theme_editor__edit_code">Modifier le code</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Aucun code défini.</string>
|
||||
<string name="settings__theme_editor__add_code">Ajouter un code clé</string>
|
||||
<string name="settings__theme_editor__edit_code">Modifier le code de la clé</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Appliquer la règle à tous les éléments cibles.</string>
|
||||
<string name="settings__theme_editor__codes_defined">Appliquer la règle uniquement aux éléments cibles avec les codes clés suivants :</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Ce code clé est déjà défini.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Ce code clé n\'est pas valide. Assurez-vous que le code de clé est dans la plage de {c_min} à {c_max} pour les caractères ou de {i_min} à {i_max} pour les clés spéciales internes.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Les liens suivants vous aideront à trouver le code clé correspondant :</string>
|
||||
<string name="settings__theme_editor__code_help_text">Sinon, les liens suivants vous aideront à trouver le code clé correspondant :</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Code</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">Pour trouver le code d\'une touche, utilisez le bouton situé à côté du champ de saisie du code. Une fois activé, il enregistrera la prochaine pression sur la touche et insérera le code dans le champ de saisie.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">L\'enregistrement du code clé a commencé</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">L\'enregistrement du code clé s\'est arrêté</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} doit être le clavier par défaut pour enregistrer un code de touche</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Enregistrement…</string>
|
||||
<string name="settings__theme_editor__add_property">Ajouter une propriété</string>
|
||||
<string name="settings__theme_editor__edit_property">Modifier la propriété</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Une propriété portant ce nom existe déjà dans la règle actuelle.</string>
|
||||
@@ -127,6 +134,7 @@
|
||||
<string name="snygg__rule_element__defines_description">Définissez des variables dans cette règle pour réutiliser des couleurs ou des tailles courantes dans votre feuille de style.</string>
|
||||
<string name="snygg__rule_element__keyboard">Fenêtre du clavier</string>
|
||||
<string name="snygg__rule_element__key">Touche</string>
|
||||
<string name="snygg__rule_element__key_hint">Indice clé</string>
|
||||
<string name="snygg__rule_element__key_popup">Pop-up de touche</string>
|
||||
<string name="snygg__rule_element__clipboard_header">En-tête du presse-papiers</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Élément du Presse-papiers</string>
|
||||
@@ -135,6 +143,8 @@
|
||||
<string name="snygg__rule_element__one_handed_panel">Panneau à une main</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_row">Rangée principale de la barre intelligente</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_row">Rangée secondaire de la barre intelligente</string>
|
||||
<string name="snygg__rule_element__smartbar_primary_actions_toggle">Activation des actions primaires de la barre intelligente</string>
|
||||
<string name="snygg__rule_element__smartbar_secondary_actions_toggle">Activation des actions secondaires de la barre intelligente</string>
|
||||
<string name="snygg__rule_element__smartbar_quick_action">Action rapides de la barre intelligente</string>
|
||||
<string name="snygg__rule_element__smartbar_key">Touche de barre intelligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Mot candidat de la barre intelligente</string>
|
||||
@@ -182,6 +192,7 @@
|
||||
<string name="snygg__property_value__dp_size">Taille (dp)</string>
|
||||
<string name="snygg__property_value__sp_size">Taille (sp)</string>
|
||||
<string name="snygg__property_value__percentage_size">Taille (%)</string>
|
||||
<string name="snygg__property_value__defined_var">Référence du Var</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Sons & Vibration</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Retour audio / Sons</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Activer le retour audio</string>
|
||||
@@ -236,6 +247,8 @@
|
||||
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Appui sur la touche</string>
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">Visibilité du popup</string>
|
||||
<string name="pref__keyboard__popup_enabled__summary" comment="Preference summary">Afficher un pop-up lors de l\'appui d\'une touche</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__label" comment="Preference title">Les accents comprennent des popups de symboles</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__summary" comment="Preference summary">Ajoute des popups de symboles aux accents de la mise en page par défaut</string>
|
||||
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Délai d\'appui prolongé</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Espace pour revenir aux caractères</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Retour automatique aux caractères depuis les symboles et les nombres</string>
|
||||
@@ -243,8 +256,12 @@
|
||||
<string name="settings__smartbar__title" comment="Title of Smartbar screen">Barre intelligente</string>
|
||||
<string name="pref__smartbar__enabled__label" comment="Preference title">Activer la Barre Intelligente</string>
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Sera affiché au dessus du clavier</string>
|
||||
<string name="pref__smartbar__flip_toggles__label" comment="Preference title">Boutons à bascule</string>
|
||||
<string name="pref__smartbar__flip_toggles__summary" comment="Preference summary">La rangée d\'action bascule</string>
|
||||
<string name="pref__smartbar__any_row_type__label" comment="Preference title">Disposition des rangs</string>
|
||||
<string name="pref__smartbar__group_primary_actions__label" comment="Preference group title">Actions principales</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__label" comment="Preference title">Agrandir/réduire automatiquement</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__summary" comment="Preference summary">Extension/réduction automatique de la ligne d\'action primaire en fonction de l\'état actuel</string>
|
||||
<string name="pref__smartbar__group_secondary_actions__label" comment="Preference group title">Actions secondaires</string>
|
||||
<string name="pref__smartbar__secondary_actions_enabled__label" comment="Preference title">Afficher la ligne d\'actions secondaires</string>
|
||||
<!-- Typing strings -->
|
||||
@@ -647,7 +664,14 @@
|
||||
<string name="enum__secondary_row_placement__below_primary__description" comment="Enum value description">Placer la ligne secondaire entre la ligne principale et le clavier de texte</string>
|
||||
<string name="enum__secondary_row_placement__overlay_app_ui" comment="Enum value label">Superposer l\'interface utilisateur de l\'application</string>
|
||||
<string name="enum__secondary_row_placement__overlay_app_ui__description" comment="Enum value description">Place la ligne secondaire en superposition au-dessus de l\'interface utilisateur de l\'application, sans affecter la hauteur résultante de l\'interface utilisateur du clavier. Notez que ce placement peut entraîner un dépassement partiel du champ de saisie de l\'application</string>
|
||||
<string name="enum__shape_corner__top_start" comment="Enum value label">Top départ</string>
|
||||
<string name="enum__shape_corner__top_end" comment="Enum value label">Top fin</string>
|
||||
<string name="enum__shape_corner__bottom_end" comment="Enum value label">Extrémité inférieure</string>
|
||||
<string name="enum__shape_corner__bottom_start" comment="Enum value label">Extrémité supérieure</string>
|
||||
<string name="enum__smartbar_row_type__quick_actions" comment="Enum value label">Actions rapides</string>
|
||||
<string name="enum__smartbar_row_type__quick_actions__description" comment="Enum value description">Actions rapides pouvant être organisées sous forme de rangées avec un menu de débordement</string>
|
||||
<string name="enum__smartbar_row_type__clipboard_cursor_tools" comment="Enum value label">Outils du curseur du presse-papiers</string>
|
||||
<string name="enum__smartbar_row_type__clipboard_cursor_tools__description" comment="Enum value description">Rame avec les outils les plus couramment utilisés pour le presse-papiers et le déplacement du curseur</string>
|
||||
<string name="enum__snygg_level__basic" comment="Enum value label">Standard</string>
|
||||
<string name="enum__snygg_level__basic__description" comment="Enum value description">Seules les propriétés de couleur sont affichées, les propriétés et les règles sont traduites.</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Avancé</string>
|
||||
|
||||
@@ -93,13 +93,9 @@
|
||||
<string name="settings__theme_editor__add_rule">Szabály hozzáadása</string>
|
||||
<string name="settings__theme_editor__edit_rule">Szabály szerkesztése</string>
|
||||
<string name="settings__theme_editor__rule_element">Cél elem</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kódok</string>
|
||||
<string name="settings__theme_editor__rule_groups">Csoportok</string>
|
||||
<string name="settings__theme_editor__rule_modes">Módok</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Választók</string>
|
||||
<string name="settings__theme_editor__add_code">Kód hozzáadása</string>
|
||||
<string name="settings__theme_editor__edit_code">Kód szerkesztése</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Nincs kód definiálva.</string>
|
||||
<string name="settings__theme_editor__add_property">Tulajdonság hozzáadása</string>
|
||||
<string name="settings__theme_editor__edit_property">Tulajdonság szerkesztése</string>
|
||||
<string name="settings__theme_editor__property_already_exists">A jelenlegi szabályon belül egy tulajdonság már létezik ezzel a névvel.</string>
|
||||
@@ -149,11 +145,19 @@
|
||||
<string name="snygg__property_value__defined_var">Változóhivatkozás</string>
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Hangok és rezgés</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Hangvisszajelzés engedélyezése</string>
|
||||
<string name="pref__input_feedback__audio_ignore_system_settings__label" comment="Preference title">A rendszer hangbeállításainka figyelmen kívül hagyása</string>
|
||||
<string name="pref__input_feedback__audio_ignore_system_settings__label" comment="Preference title">A rendszer hangbeállításainak figyelmen kívül hagyása</string>
|
||||
<string name="pref__input_feedback__audio_ignore_system_settings__summary" comment="Preference summary">Az alábbi beállítások használata, akkor is ha a hang le van tiltva a rendszerben. Nem működik, ha a rendszer csengőhang le van némítva</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_press__label" comment="Preference title">Gombnyomáshangok</string>
|
||||
<string name="pref__input_feedback__group_haptic__label" comment="Preference group title">Haptikus visszajelzés / vibráció</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__label" comment="Preference title">Haptikus visszajelzés engedélyezése</string>
|
||||
<string name="pref__input_feedback__haptic_ignore_system_settings__label" comment="Preference title">A rendszer hangbeállításainak figyelmen kívül hagyása</string>
|
||||
<string name="pref__input_feedback__haptic_ignore_system_settings__summary" comment="Preference summary">Az alábbi beállítások használata, akkor is ha a haptika le van tiltva a rendszerben</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">Rezgés időtartama</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">Rezgés erőssége</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_press__label" comment="Preference title">Gombnyomás rezgése</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_long_press__label" comment="Preference title">Hosszú gombnyomás rezgése</string>
|
||||
<string name="pref__input_feedback__any_feat_key_repeated_action__summary" comment="Preference summary">pl. törlés gomb</string>
|
||||
<string name="pref__input_feedback__any_feat_gesture_swipe__summary" comment="Preference summary">nincs implementálva</string>
|
||||
<string name="settings__keyboard__title" comment="Title of Keyboard preferences screen">Billentyűzet</string>
|
||||
<string name="pref__keyboard__number_row__label" comment="Preference title">Számsor</string>
|
||||
<string name="pref__keyboard__number_row__summary" comment="Preference summary">Számsor megjelenítése a karakterelrendezés felett</string>
|
||||
@@ -162,6 +166,8 @@
|
||||
<string name="pref__keyboard__utility_key_enabled__label" comment="Preference title">Kellékgomb megjelenítése</string>
|
||||
<string name="pref__keyboard__utility_key_enabled__summary" comment="Preference summary">Egy beállítható kellékgomb megjelenítése a szóköz mellett</string>
|
||||
<string name="pref__keyboard__utility_key_action__label" comment="Preference title">Kellékgomb művelet</string>
|
||||
<string name="pref__keyboard__space_bar_language_display_enabled__label" comment="Preference title">Nyelv megjelenítése a szóköz gombon</string>
|
||||
<string name="pref__keyboard__font_size_multiplier__label" comment="Preference title">Betűméret-szorzó</string>
|
||||
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Elrendezés</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Egykezes mód</string>
|
||||
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Billentyűzet szélessége egykezes módban</string>
|
||||
@@ -184,6 +190,7 @@
|
||||
<string name="settings__typing__title" comment="Title of Typing experience screen">Javaslatok és javítások</string>
|
||||
<string name="pref__suggestion__title" comment="Preference group title">Javaslatok</string>
|
||||
<string name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">Vágólap tartalom javaslatok</string>
|
||||
<string name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title">Vágólap javaslatok időtúllépése</string>
|
||||
<string name="pref__correction__title" comment="Preference group title">Javítások</string>
|
||||
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Automatikusan nagy kezdőbetű</string>
|
||||
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Kezdje nagybetűvel a szavakat a bemeneti környezet alapján</string>
|
||||
@@ -193,10 +200,11 @@
|
||||
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Ha kétszer megérinti a szóközt, beszúr egy pontot, amelyet egy szóköz követ</string>
|
||||
<string name="settings__dictionary__title" comment="Title of the User dictionaries screen">Felhasználói szótárak</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">Rendszer felhasználói szótárának engedélyezése</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">A rendszer felhasználói szótárban tárolt szavak ajánlása</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__label" comment="Preference title">Rendszer felhasználói szótárának kezelése</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">Elemek hozzáadása, megtekintése és eltávolítása a rendszer felhasználói szótárból</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__label" comment="Preference title">Belső felhasználói szótár engedélyezése</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__summary" comment="Preference summary">Tárolt szavak ajánlása a belső felhasználói szótárból</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__summary" comment="Preference summary">A belső felhasználói szótárban tárolt szavak ajánlása</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__label" comment="Preference title">Belső felhasználói szótár kezelése</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__summary" comment="Preference summary">Elemek hozzáadása, megtekintése és eltávolítása a belső felhasználói szótárból</string>
|
||||
<string name="settings__udm__title_floris" comment="Title of the User Dictionary Manager activity for internal">Belső felhasználói szótár</string>
|
||||
@@ -497,6 +505,7 @@
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Haladó</string>
|
||||
<string name="enum__snygg_level__developer" comment="Enum value label">Fejlesztő</string>
|
||||
<string name="enum__spelling_language_mode__use_system_languages" comment="Enum value label">Rendszernyelvek használata</string>
|
||||
<string name="enum__spelling_language_mode__use_keyboard_subtypes" comment="Enum value label">Billentyűzet altípusok használata</string>
|
||||
<string name="enum__swipe_action__no_action" comment="Enum value label">Nincs művelet</string>
|
||||
<string name="enum__swipe_action__cycle_to_previous_keyboard_mode" comment="Enum value label">Váltás az előző billentyűzetmódra</string>
|
||||
<string name="enum__swipe_action__cycle_to_next_keyboard_mode" comment="Enum value label">Váltás a következő billentyűzetmódra</string>
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<string name="app_name">FlorisBoard</string>
|
||||
<string name="key__phone_pause" comment="Label for the Pause key in the telephone keyboard layout">Jeda</string>
|
||||
<string name="key__phone_wait" comment="Label for the Wait key in the telephone keyboard layout">Tunggu</string>
|
||||
<string name="key_popup__threedots_alt" comment="Content description for the three-dots icon in a key popup">Ikon tiga titik. Jika terlihat, menandakan bahwa huruf-huruf tambahan bisa digunakan saat ditekan lama.</string>
|
||||
<string name="key_popup__threedots_alt" comment="Content description for the three-dots icon in a key popup">Tombol tiga titik. Jika terlihat, menandakan bahwa lebih banyak huruf dapat digunakan jika ditekan lama.</string>
|
||||
<!-- One-handed strings -->
|
||||
<string name="one_handed__close_btn_content_description" comment="Content description for the one-handed close button">Tutup mode satu-tangan.</string>
|
||||
<string name="one_handed__move_start_btn_content_description" comment="Content description for the one-handed move to left button">Pindahkan keyboard ke kiri.</string>
|
||||
<string name="one_handed__move_end_btn_content_description" comment="Content description for the one-handed move to right button">Pindahkan keyboard ke kanan.</string>
|
||||
<!-- Media strings -->
|
||||
<string name="settings__media__title">Emoji</string>
|
||||
<string name="settings__media__title">Emoticon</string>
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emoji</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emotikon</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
@@ -104,16 +104,23 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Lembar gaya ini tidak memiliki aturan yang didefinisikan. Tambahkan sebuah aturan untuk mulai menyesuaikan lembar gaya ini.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Aturan lembar gaya ini telah didefinisikan.</string>
|
||||
<string name="settings__theme_editor__rule_element">Elemen target</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kode</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kode target tombol</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grup</string>
|
||||
<string name="settings__theme_editor__rule_modes">Mode</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Pemilih</string>
|
||||
<string name="settings__theme_editor__add_code">Tambahkan kode</string>
|
||||
<string name="settings__theme_editor__edit_code">Edit kode</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Tidak ada kode yang didefinisikan.</string>
|
||||
<string name="settings__theme_editor__add_code">Tambahkan kode tombol</string>
|
||||
<string name="settings__theme_editor__edit_code">Edit kode tombol</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Tetapkan aturan ke semua elemen target.</string>
|
||||
<string name="settings__theme_editor__codes_defined">Tetapkan aturan saja ke element target dengan kode tombol berikut:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Kode tombol ini telah didefinisikan.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Kode tombol ini tidak valid. Pastikan bahwa kode kunci dalam jangkauan dari {c_min} sampai {c_max} untuk karakter atau {i_min} sampai {i_max} untuk tombol internal spesial.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Tautan berikut ini akan membantu Anda menemukan kode tombol yang sesuai:</string>
|
||||
<string name="settings__theme_editor__code_help_text">Secara alternatif tautan berikut ini akan membantu Anda menemukan kode tombol yang sesuai:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Kode</string>
|
||||
<string name="settings__theme_editor__code_recording_help_text">Untuk menemukan kode dari sebuah tombol, gunakan tombol di samping kolom input kode. Ketika diaktifkan, itu akan merekam tekanan tombol berikut dan akan mengisi kodenya ke kolom input.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">Rekaman kode tombol dimulai</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">Rekaman kode tombol dihentikan</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} harus ditetapkan sebagai keyboard default untuk merekam kode tombol</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Merekam…</string>
|
||||
<string name="settings__theme_editor__add_property">Tambahkan properti</string>
|
||||
<string name="settings__theme_editor__edit_property">Edit properti</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Sebuah properti dengan nama ini sudah ada dalam aturan saat ini.</string>
|
||||
|
||||
@@ -103,16 +103,11 @@
|
||||
<string name="settings__theme_editor__no_rules_defined">Questo file di stile non ha regole definite. Aggiungi una regola per iniziare a personalizzare questo file di stile.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Questa regola del file di stile è già definita.</string>
|
||||
<string name="settings__theme_editor__rule_element">Elemento di destinazione</string>
|
||||
<string name="settings__theme_editor__rule_codes">Codici</string>
|
||||
<string name="settings__theme_editor__rule_groups">Gruppi</string>
|
||||
<string name="settings__theme_editor__rule_modes">Modalità</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selettori</string>
|
||||
<string name="settings__theme_editor__add_code">Aggiungi codice</string>
|
||||
<string name="settings__theme_editor__edit_code">Modifica codice</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Nessun codice definito.</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Questo codice di tasto è già definito.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Questo codice di tasto non è valido. Assicurarsi che il codice di tasto sia compreso nell\'intervallo da {c_min} a {c_max} per i caratteri o da {i_min} a {i_max} per tasti speciali interni.</string>
|
||||
<string name="settings__theme_editor__code_help_text">I seguenti link ti aiuteranno a trovare il codice di tasto corrispondente:</string>
|
||||
<string name="settings__theme_editor__add_property">Aggiungi proprietà</string>
|
||||
<string name="settings__theme_editor__edit_property">Modifica proprietà</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Una proprietà con questo nome esiste già all\'interno della regola corrente.</string>
|
||||
|
||||
@@ -103,16 +103,11 @@
|
||||
<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_modes">モード</string>
|
||||
<string name="settings__theme_editor__rule_selectors">セレクター</string>
|
||||
<string name="settings__theme_editor__add_code">コードを追加</string>
|
||||
<string name="settings__theme_editor__edit_code">コードを編集</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">コードが定義されていません。</string>
|
||||
<string name="settings__theme_editor__code_already_exists">このキーコードはすでに定義されています。</string>
|
||||
<string name="settings__theme_editor__code_invalid">このキーコードは無効です。 キーコードが、文字の場合は {c_min} から {c_max} の範囲内、内部特殊キーの場合は {i_min} から {i_max} の範囲内にあることを確認してください。</string>
|
||||
<string name="settings__theme_editor__code_help_text">次のリンクは、対応するキーコードを見つけるのに役立ちます:</string>
|
||||
<string name="settings__theme_editor__add_property">プロパティを追加</string>
|
||||
<string name="settings__theme_editor__edit_property">プロパティを編集</string>
|
||||
<string name="settings__theme_editor__property_already_exists">この名前のプロパティは、現在のルール内にすでに存在します。</string>
|
||||
@@ -178,8 +173,116 @@
|
||||
<string name="snygg__property_value__explicit_inherit">継承</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>
|
||||
<string name="snygg__property_value__cut_corner_shape_percent">カットコーナー形状(%)</string>
|
||||
<string name="snygg__property_value__rounded_corner_shape_dp">丸みを帯びた角の形(dp)</string>
|
||||
<string name="snygg__property_value__rounded_corner_shape_percent">丸みを帯びた角の形状(%)</string>
|
||||
<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>
|
||||
<string name="pref__input_feedback__audio_enabled__summary" comment="Preference summary">システム設定に応じて、入力イベントのサウンドを再生します</string>
|
||||
<string name="pref__input_feedback__audio_ignore_system_settings__label" comment="Preference title">システムオーディオ設定を無効</string>
|
||||
<string name="pref__input_feedback__audio_ignore_system_settings__summary" comment="Preference summary">システムでオーディオが無効になっている場合でも、以下の設定を使用してください。 システムの着信音がミュートされている場合は機能しません</string>
|
||||
<string name="pref__input_feedback__audio_volume__label" comment="Preference title">入力イベントの音量</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_press__label" comment="Preference title">キーを押したときのサウンド</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_long_press__label" comment="Preference title">キーを長く押した時のサウンド</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_repeated_action__label" comment="Preference title">キーリピートアクションサウンド</string>
|
||||
<string name="pref__input_feedback__audio_feat_gesture_swipe__label" comment="Preference title">ジェスチャーをスワイプした時のサウンド</string>
|
||||
<string name="pref__input_feedback__audio_feat_gesture_moving_swipe__label" comment="Preference title">ジェスチャーを移動した時のスワイプサウンド</string>
|
||||
<string name="pref__input_feedback__group_haptic__label" comment="Preference group title">触覚フィードバック/バイブレーション</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__label" comment="Preference title">触覚フィードバックを有効</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__summary" comment="Preference summary">システム設定に応じて、入力イベントを振動させる</string>
|
||||
<string name="pref__input_feedback__haptic_ignore_system_settings__label" comment="Preference title">システムの触覚設定を無視</string>
|
||||
<string name="pref__input_feedback__haptic_ignore_system_settings__summary" comment="Preference summary">システムでハプティックが無効になっている場合でも、以下の設定を使用してください</string>
|
||||
<string name="pref__input_feedback__haptic_use_vibrator__label" comment="Preference title">バイブレーションを直接トリガー</string>
|
||||
<string name="pref__input_feedback__haptic_use_vibrator__summary" comment="Preference summary">Androidの触覚フィードバック機能セットを使用する代わりに、バイブレーションを直接トリガーします</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">バイブレーション持続時間</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">バイブレーションの強さ</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__summary_no_amplitude_ctrl" comment="Preference summary">この機能にはハードウェア振幅制御のサポートが必要ですが、これはこのデバイスにはありません</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__summary_unsupported_android_version" comment="Preference summary">この機能には、Android8.0以降でのみ利用可能な振幅制御のサポートが必要です。</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_press__label" comment="Preference title">キーバイブレーション</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_long_press__label" comment="Preference title">キーを長く押した時の振動</string>
|
||||
<string name="pref__input_feedback__haptic_feat_key_repeated_action__label" comment="Preference title">キーリピートアクションバイブレーション</string>
|
||||
<string name="pref__input_feedback__haptic_feat_gesture_swipe__label" comment="Preference title">ジェスチャーをスワイプした時の振動</string>
|
||||
<string name="pref__input_feedback__haptic_feat_gesture_moving_swipe__label" comment="Preference title">ジェスチャーを移動した時のスワイプ振動</string>
|
||||
<string name="pref__input_feedback__any_feat_key_press__summary" comment="Preference summary">例えば キー、ボタン、絵文字タブ</string>
|
||||
<string name="pref__input_feedback__any_feat_key_long_press__summary" comment="Preference summary">例えば ポップアップメニュー</string>
|
||||
<string name="pref__input_feedback__any_feat_key_repeated_action__summary" comment="Preference summary">例えばキーを削除</string>
|
||||
<string name="pref__input_feedback__any_feat_gesture_swipe__summary" comment="Preference summary">実装されていません</string>
|
||||
<string name="pref__input_feedback__any_feat_gesture_moving_swipe__summary" comment="Preference summary">例えば カーソルコントロールスワイプ</string>
|
||||
<string name="settings__keyboard__title" comment="Title of Keyboard preferences screen">キーボード</string>
|
||||
<string name="pref__keyboard__number_row__label" comment="Preference title">行数</string>
|
||||
<string name="pref__keyboard__number_row__summary" comment="Preference summary">文字レイアウトの上に数字の行を表示する</string>
|
||||
<string name="pref__keyboard__hinted_number_row_mode__label" comment="Preference title">ヒント付きの数字の行</string>
|
||||
<string name="pref__keyboard__hinted_symbols_mode__label" comment="Preference title">ヒント記号</string>
|
||||
<string name="pref__keyboard__utility_key_enabled__label" comment="Preference title">ユーティリティキーを表示</string>
|
||||
<string name="pref__keyboard__utility_key_enabled__summary" comment="Preference summary">スペースバーの横に設定可能なユーティリティキーを表示します</string>
|
||||
<string name="pref__keyboard__utility_key_action__label" comment="Preference title">ユーティリティキーアクション</string>
|
||||
<string name="pref__keyboard__space_bar_language_display_enabled__label" comment="Preference title">スペースバーに言語を表示する</string>
|
||||
<string name="pref__keyboard__space_bar_language_display_enabled__summary" comment="Preference summary">スペースバーに現在アクティブな言語名を表示します</string>
|
||||
<string name="pref__keyboard__font_size_multiplier__label" comment="Preference title">フォントサイズの倍率</string>
|
||||
<string name="pref__keyboard__group_layout__label" comment="Preference group title">レイアウト</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">片手モード</string>
|
||||
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">片手モード時のキーボードの幅</string>
|
||||
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">横向き時のフルスクリーンの入力</string>
|
||||
<string name="pref__keyboard__height_factor__label" comment="Preference title">キーボードの高さ</string>
|
||||
<string name="pref__keyboard__key_spacing__label" comment="Preference title">キーの間隔</string>
|
||||
<string name="pref__keyboard__bottom_offset__label" comment="Preference title">ボトムオフセット</string>
|
||||
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">キーを押す時の設定</string>
|
||||
<string name="pref__keyboard__popup_enabled__label" comment="Preference title">ポップアップの可視性</string>
|
||||
<string name="pref__keyboard__popup_enabled__summary" comment="Preference summary">キーを押すとポップアップが表示されます</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__label" comment="Preference title">アクセントにシンボルポップアップを含む</string>
|
||||
<string name="pref__keyboard__merge_hint_popups_enabled__summary" comment="Preference summary">デフォルトのレイアウトのアクセントにシンボルポップアップを追加します</string>
|
||||
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">長くキーを押した時の待ち時間</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">スペースバーを文字に切り替える</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">記号または数字の場合、自動的に文字に戻ります</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="settings__smartbar__title" comment="Title of Smartbar screen">スマートバー</string>
|
||||
<string name="pref__smartbar__enabled__label" comment="Preference title">スマートバーを有効</string>
|
||||
<string name="pref__smartbar__enabled__summary" comment="Preference summary">キーボードの上に表示されます</string>
|
||||
<string name="pref__smartbar__flip_toggles__label" comment="Preference title">トグルボタンを切り替える</string>
|
||||
<string name="pref__smartbar__flip_toggles__summary" comment="Preference summary">アクション行の切り替えを反転します</string>
|
||||
<string name="pref__smartbar__any_row_type__label" comment="Preference title">行レイアウト</string>
|
||||
<string name="pref__smartbar__group_primary_actions__label" comment="Preference group title">プライマリーアクション</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__label" comment="Preference title">自動的に拡張/折りたたみ</string>
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__summary" comment="Preference summary">現在の状態に基づいてプライマリーアクション行を自動的に展開/折りたたみます</string>
|
||||
<string name="pref__smartbar__group_secondary_actions__label" comment="Preference group title">セカンダリーアクション</string>
|
||||
<string name="pref__smartbar__secondary_actions_enabled__label" comment="Preference title">二次アクション行を表示</string>
|
||||
<!-- Typing strings -->
|
||||
<string name="settings__typing__title" comment="Title of Typing experience screen">提案& 訂正</string>
|
||||
<string name="pref__suggestion__title" comment="Preference group title">提案</string>
|
||||
<string name="pref__suggestion__api30_inline_suggestions_enabled__summary" comment="Preference summary">オートフィルサービスによって提供されるインライン提案を表示する</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__suggestion__clipboard_content_timeout__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>
|
||||
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">CapsLock状態を維持</string>
|
||||
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">別のテキストフィールドに移動しても、CapsLockはオンのままになります</string>
|
||||
<string name="pref__correction__double_space_period__label" comment="Preference title">ダブルスペースでピリオドを入力</string>
|
||||
<string name="pref__correction__double_space_period__summary" comment="Preference summary">スペースバーを2回タップすると、ピリオドの後にスペースが挿入されます</string>
|
||||
<string name="settings__dictionary__title" comment="Title of the User dictionaries screen">ユーザー辞書</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">システムユーザー辞書を有効化</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">システムユーザー辞書に保存されている単語を提案します</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__label" comment="Preference title">システムユーザー辞書を管理</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">システムユーザー辞書のエントリを追加、表示、および削除をします</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__label" comment="Preference title">内部ユーザー辞書を有効化</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__summary" comment="Preference summary">内部ユーザー辞書に保存されている単語を提案します</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__label" comment="Preference title">内部ユーザー辞書を管理</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__summary" comment="Preference summary">内部ユーザー辞書のエントリを追加、表示、および削除をします</string>
|
||||
<string name="settings__udm__title_floris" comment="Title of the User Dictionary Manager activity for internal">内部ユーザー辞書</string>
|
||||
<string name="settings__udm__title_system" comment="Title of the User Dictionary Manager activity for system">システムユーザー辞書</string>
|
||||
<string name="settings__udm__no_words_in_dictionary" comment="String to show if no words are present in the dictionary">このユーザー辞書には単語が含まれていません。</string>
|
||||
<string name="settings__udm__word_summary_freq" comment="Summary label for a word entry. The decimal placeholder inserts the frequency for the word it summarizes.">頻度:{freq}</string>
|
||||
<string name="settings__udm__word_summary_freq_shortcut" comment="Summary label for a word entry. The first placeholder inserts the frequency for the word it summarizes, the second placeholder the shortcut defined.">頻度:{freq} | ショートカット:{shortcut}</string>
|
||||
<string name="settings__udm__all_languages" comment="Label of the For all languages entry in the language list">すべての言語</string>
|
||||
<!-- Spelling UI strings -->
|
||||
<!-- About UI strings -->
|
||||
<!-- Setup UI strings -->
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
<string name="one_handed__move_start_btn_content_description" comment="Content description for the one-handed move to left button">키보드를 왼쪽으로 옮깁니다.</string>
|
||||
<string name="one_handed__move_end_btn_content_description" comment="Content description for the one-handed move to right button">키보드를 오른쪽으로 옮깁니다.</string>
|
||||
<!-- Media strings -->
|
||||
<string name="settings__media__title">이모지</string>
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">이모지</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">이모티콘</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">카오모지</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">최대로 표시할 수 있는 최근 사용한 이모지</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">선호하는 이모지 피부톤</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">선호하는 이모지 헤어 스타일</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">스마일리 & 이모티콘</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">사람 & 몸</string>
|
||||
@@ -22,33 +26,79 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">사물</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">기호</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">깃발</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">최근에 사용한 이모지가 없습니다. 이모지를 입력하기 시작하면 여기에 자동으로 표시됩니다.</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji}가 최근 사용 기록에서 삭제되었습니다</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="smartbar__quick_action__exit_editing" comment="Content-description for the exit editing layout button in Smartbar">텍스트 수정 패널에서 나갑니다.</string>
|
||||
<string name="smartbar__quick_action__open_settings" comment="Content-description for the settings quick action in Smartbar">설정을 엽니다.</string>
|
||||
<string name="smartbar__quick_action__switch_to_editing_context" comment="Content-description for the editing quick action in Smartbar">텍스트 수정 패널로 전환</string>
|
||||
<string name="smartbar__quick_action__switch_to_media_context" comment="Content-description for the media quick action in Smartbar">미디어 입력 보기로 전환</string>
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">설정</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">설정을 사용해 보세요.</string>
|
||||
<string name="settings__help" comment="General label for help buttons in Settings">도움말</string>
|
||||
<string name="settings__default" comment="General string which is used when a preference has the default value set">기본</string>
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">시스템 기본 설정</string>
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">FlorisBoard가 시스템 설정에서 활성화되어 있지 않아 입력 방법으로 설정할 수 없습니다. 여기를 눌러 문제를 해결할 수 있습니다.</string>
|
||||
<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__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__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">하위 유형 편집</string>
|
||||
<string name="settings__localization__subtype_characters_layout" comment="Label for layout dropdown in subtype dialog">문자 배열</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).">통화 설정</string>
|
||||
<string name="settings__localization__subtype_select_locale" comment="Subtype select language title">언어 선택</string>
|
||||
<string name="settings__localization__subtype_search_locale_placeholder" comment="Subtype search language placeholder">언어 검색하기</string>
|
||||
<string name="settings__localization__subtype_search_locale_not_found" comment="Subtype search language not found">\"{search_term}\"과 일치하는 언어를 찾지 못했습니다.</string>
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">모두 보기</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">테마</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">테마 모드</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">일출 시간</string>
|
||||
<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__any_theme__label" comment="Label of the theme selector preference">선택한 테마</string>
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">내부 저장소</string>
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">밝은 테마 선택</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">어두운 테마 선택</string>
|
||||
<string name="settings__theme_manager__title_manage" comment="Title of the theme manager screen for managing installed and custom themes">설치된 테마 관리</string>
|
||||
<string name="settings__theme_editor__rule_groups">그룹</string>
|
||||
<string name="snygg__property_name__width">너비</string>
|
||||
<string name="snygg__property_name__height">높이</string>
|
||||
<string name="snygg__property_name__border_color">테두리 색</string>
|
||||
<string name="snygg__property_name__border_style">테두리 스타일</string>
|
||||
<string name="snygg__property_name__border_width">테두리 두께</string>
|
||||
<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="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">진동 지속 시간</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">진동 세기</string>
|
||||
<string name="settings__keyboard__title" comment="Title of Keyboard preferences screen">키보드</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">한 손 조작 모드</string>
|
||||
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">한 손 조작 모드 키보드 너비</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="pref__smartbar__primary_actions_auto_expand_collapse__label" comment="Preference title">자동 확장/축소</string>
|
||||
<!-- Typing strings -->
|
||||
<!-- Spelling UI strings -->
|
||||
<!-- About UI strings -->
|
||||
<string name="about__view_source_code" comment="Label of View source code button in About">소스 코드</string>
|
||||
<string name="about__license__title" comment="Title of Open-source licenses dialog">오픈 소스 라이선스</string>
|
||||
<string name="about__version__title" comment="Preference title">버전</string>
|
||||
<!-- Setup UI strings -->
|
||||
<string name="setup__title" comment="Title of Setup">환영합니다!</string>
|
||||
<!-- Back up & Restore -->
|
||||
<!-- Crash Dialog strings -->
|
||||
<!-- Clipboard strings -->
|
||||
<string name="clipboard__header_title">클립보드</string>
|
||||
<string name="clipboard__group_pinned">고정됨</string>
|
||||
<string name="clipboard__group_other">기타</string>
|
||||
<string name="clip__delete_item">삭제</string>
|
||||
<string name="clip__paste_item">붙여넣기</string>
|
||||
<string name="settings__clipboard__title">클립보드</string>
|
||||
<!-- Devtools strings -->
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__meta__homepage">홈페이지</string>
|
||||
<string name="ext__meta__id">아이디</string>
|
||||
<string name="ext__meta__version">버전</string>
|
||||
<!-- Action strings -->
|
||||
<!-- Error strings (generic) -->
|
||||
<!-- General strings -->
|
||||
|
||||
@@ -100,13 +100,9 @@
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Piştî diyalogan klavyeyê nîşande</string>
|
||||
<string name="settings__theme_editor__add_rule">Rêbazekê tevlî bike</string>
|
||||
<string name="settings__theme_editor__edit_rule">Rêbazê serrast bike</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kod</string>
|
||||
<string name="settings__theme_editor__rule_groups">Kom</string>
|
||||
<string name="settings__theme_editor__rule_modes">Moda</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Hilbijêr</string>
|
||||
<string name="settings__theme_editor__add_code">Koda lê zêde bike</string>
|
||||
<string name="settings__theme_editor__edit_code">Koda sererastkirinê</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Tu kod nehatine pênasekirin.</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Ev koda mifteyan jixwe hatîye pênasekirin.</string>
|
||||
<string name="snygg__rule_element__key">Kilîd</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Darikê navîgasyonê yê pergalê</string>
|
||||
@@ -331,6 +327,8 @@
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">هەڵگرتنی شتە لەبەرگیراوەکان بۆ هێشتنەوە</string>
|
||||
<string name="pref__clipboard__clean_up_old__label">Berhemên kevin paqij bikin</string>
|
||||
<string name="pref__clipboard__clean_up_after__label">Piştî kelûpelên kevin paqij bikin</string>
|
||||
<string name="pref__clipboard__max_history_size__label">Mezinahiya dîroka Maxê</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__label">Dîroka efektên klîbê yên sereke paqij bike</string>
|
||||
<!-- Devtools strings -->
|
||||
<string name="devtools__show_primary_clip__label" comment="Label of Show primary clip in Devtools">پیشاندانی لەبەرگیراوە بنەڕەتیەکان</string>
|
||||
<string name="devtools__show_primary_clip__summary" comment="Summary of Show primary clip in Devtools">پیشاندانی لەبەرگیراوەی بنەڕەتی سیستەم</string>
|
||||
@@ -412,6 +410,9 @@
|
||||
<string name="enum__secondary_row_placement__below_primary__description" comment="Enum value description">پیشاندانی ڕیزی دووەم لەنێوان ڕیزی یەکەم و تەختەکلیل</string>
|
||||
<string name="enum__secondary_row_placement__overlay_app_ui" comment="Enum value label">لەسەروی تەختەکلیل</string>
|
||||
<string name="enum__secondary_row_placement__overlay_app_ui__description" comment="Enum value description">پیشادانی ڕیزی دووەم لەسەروی تەختەکلیلەکە، بەبێ گەورەکردنی قەبارەی تەختەکلیل، لەوانەیە ھەندێ بەش بەباشی دەرنەکەون</string>
|
||||
<string name="enum__snygg_level__basic" comment="Enum value label">Bingehîn</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Pêşketî</string>
|
||||
<string name="enum__snygg_level__developer" comment="Enum value label">Pêşdebir</string>
|
||||
<string name="enum__spelling_language_mode__use_system_languages" comment="Enum value label">Zimanên systemê bi kar bîne</string>
|
||||
<string name="enum__spelling_language_mode__use_keyboard_subtypes" comment="Enum value label">Cureyên jêr ên klavyeyê bi kar bîne</string>
|
||||
<string name="enum__swipe_action__no_action" comment="Enum value label">Bê çalakî</string>
|
||||
@@ -429,7 +430,10 @@
|
||||
<string name="enum__swipe_action__move_cursor_start_of_page" comment="Enum value label">Nîşanek bibe destpêka rûpelê</string>
|
||||
<string name="enum__swipe_action__move_cursor_end_of_page" comment="Enum value label">Nîşanek ber bi dawiya rûpelê ve bibe</string>
|
||||
<string name="enum__swipe_action__shift" comment="Enum value label">Shift</string>
|
||||
<string name="enum__swipe_action__redo" comment="Enum value label">Redo</string>
|
||||
<string name="enum__swipe_action__undo" comment="Enum value label">Vegerîne</string>
|
||||
<string name="enum__swipe_action__select_characters_precisely" comment="Enum value label">Karakteran bi rastî jê bibe</string>
|
||||
<string name="enum__swipe_action__select_words_precisely" comment="Enum value label">Peyvan bi rastî jê bibire</string>
|
||||
<string name="enum__swipe_action__show_input_method_picker" comment="Enum value label">Hilbijêrê metoda têkerê nîşan bide</string>
|
||||
<string name="enum__swipe_action__switch_to_prev_keyboard" comment="Enum value label">Li klavyeya berê biguhere</string>
|
||||
<string name="enum__swipe_action__switch_to_prev_subtype" comment="Enum value label">Biguhere jêrtîpa berê</string>
|
||||
|
||||
@@ -103,16 +103,12 @@
|
||||
<string name="settings__theme_editor__no_rules_defined">Šī stila lapa nesatur nosacījumus. Lai to pielāgotu, jāpievieno kāds nosacījums.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Šis stila lapas nosacījums jau ir noteikts.</string>
|
||||
<string name="settings__theme_editor__rule_element">Mērķa elements</string>
|
||||
<string name="settings__theme_editor__rule_codes">Kodi</string>
|
||||
<string name="settings__theme_editor__rule_groups">Kopas</string>
|
||||
<string name="settings__theme_editor__rule_modes">Veidi</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Atlasītāji</string>
|
||||
<string name="settings__theme_editor__add_code">Pievienot kodu</string>
|
||||
<string name="settings__theme_editor__edit_code">Labot kodu</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Kodi nav noteikti.</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Šis taustiņa kods jau ir noteikts.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Šis taustiņa kods ir nederīgs. Jānodrošina, ka taustiņa kods ir starp {c_min} un {c_max} rakstzīmēm vai starp {i_min} un {i_max} iekšējiem īpašajiem taustiņiem.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Šīs saites palīdzēs atrast atbilstošo taustiņa kodu:</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Ieraksta…</string>
|
||||
<string name="settings__theme_editor__add_property">Pievienot īpašību</string>
|
||||
<string name="settings__theme_editor__edit_property">Labot īpašību</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Īpašība ar šādu nosaukumu jau pastāv pašreizējā nosacījumā.</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user