Compare commits

...

62 Commits

Author SHA1 Message Date
Patrick Goldinger
b2ec115505 Release v0.3.10-beta04 2021-03-29 14:46:14 +02:00
Patrick Goldinger
670e6ca5e1 Fix emoji ABC button not leading back to characters (#521) 2021-03-29 02:55:23 +02:00
Patrick Goldinger
f2403d00e5 Add long-press caps-lock activation vibration (#523) 2021-03-29 02:46:46 +02:00
Patrick Goldinger
224d3e00e3 Merge pull request #518 from florisboard/fix-popup-width-landscape
Adjust popups in landscape mode
2021-03-28 19:47:40 +02:00
Patrick Goldinger
e89a374ce0 Adjust popup width in landscape (#504) 2021-03-28 19:35:43 +02:00
Patrick Goldinger
538e2dd9a2 Merge pull request #514 from florisboard/suggestions-phase2-frontend
Suggestions frontend rework
2021-03-28 19:15:37 +02:00
Patrick Goldinger
1d3d85c211 Fix crash for image clipboard suggestions 2021-03-28 19:08:49 +02:00
Patrick Goldinger
d6121baca9 Polish and document candidate view 2021-03-28 18:16:59 +02:00
Patrick Goldinger
8c0337d6c9 Fix suggestions not resetting when switching apps (#429) 2021-03-27 19:53:51 +01:00
Patrick Goldinger
563a4a919d Add new candidate+clipboard suggestion view (#38, #424, #425, #426) 2021-03-27 19:45:53 +01:00
Patrick Goldinger
2f0d607d02 Potential fix for #484 2021-03-24 20:20:01 +01:00
Patrick Goldinger
65ae6c2b66 Merge pull request #491 from X-yl/clipboard-stuff
Fix for #481
2021-03-24 19:21:33 +01:00
x-yl
14513ec0f1 kotlin-ify 2021-03-24 18:07:07 +04:00
x-yl
3c58144a3d fix #481 2021-03-24 17:52:12 +04:00
Patrick Goldinger
d65b706f78 Release v0.3.10-beta03 2021-03-23 20:00:49 +01:00
Patrick Goldinger
9d820677db Update translations from Crowdin 2021-03-23 19:50:06 +01:00
Patrick Goldinger
69c52c00f6 Fix Ž key not available in Dvorak/Serbian (#381) 2021-03-23 19:43:41 +01:00
Patrick Goldinger
c8cf256577 Merge pull request #488 from florisboard/turkish-layouts
Add Turkish-Q / Turkish-F layouts
2021-03-23 14:35:11 +01:00
Patrick Goldinger
386a0999c4 Add Turkish-Q / Turkish-F layouts (#182) 2021-03-23 14:07:42 +01:00
Patrick Goldinger
d4ef2ea827 Merge pull request #486 from Netscaping/patch-1
Create gboard_night.json
2021-03-22 15:28:11 +01:00
Patrick Goldinger
381ec68e6c Merge pull request #482 from florisboard/rework-symbols-sizing
Rework symbols sizing when number row is enabled
2021-03-22 15:18:40 +01:00
Netscaping
a5706167b2 Create gboard_night.json
Since there is a Gboard Day theme I added the night version.
2021-03-22 15:17:46 +01:00
Patrick Goldinger
660871d6c8 Rework symbols sizing when number row is enabled 2021-03-22 00:55:47 +01:00
Patrick Goldinger
6607ad1739 Fix language selector size for keyboard height greater than 125% 2021-03-22 00:01:56 +01:00
Patrick Goldinger
55c1bc05f2 Add auto-switching to characters in symbols (#347) 2021-03-21 19:12:10 +01:00
Patrick Goldinger
7eb7f0ef80 Release v0.3.10-beta02 2021-03-19 19:42:08 +01:00
Patrick Goldinger
78e5e417ce Update README.md to include new beta track 2021-03-19 18:49:40 +01:00
Patrick Goldinger
ffbf7f8ea7 Merge pull request #454 from X-yl/clipboard-stuff
Added support for private clipboard and clipboard history
2021-03-19 17:49:16 +01:00
Patrick Goldinger
27cc4897c3 Merge pull request #479 from florisboard/fix-import-theme-crash
Fix import theme crash for big files
2021-03-19 17:18:49 +01:00
Patrick Goldinger
e5111a8efe Fix import theme crash for big files (#465) 2021-03-19 17:04:48 +01:00
Patrick Goldinger
80fd5ca84a Add beta metadata 2021-03-19 00:57:11 +01:00
x-yl
e8f2c6ce74 fix bug when history size is reduced 2021-03-18 23:21:50 +04:00
x-yl
5676cbf18e Stupid telegram, not using ContentResolver... smh 2021-03-18 17:50:48 +04:00
x-yl
2bdaea6189 revoke URI permissions, support API <25 2021-03-18 17:10:28 +04:00
Patrick Goldinger
da2287a739 Fix symbols layouts applying the caps state once again (#298) 2021-03-17 23:29:58 +01:00
Patrick Goldinger
3fafe0fac8 Release v0.3.10-beta01 2021-03-17 14:48:31 +01:00
x-yl
86042bb1e1 make popup buttons extend to the edge of popup 2021-03-17 15:30:22 +04:00
x-yl
c99673ff1d mime type fixes, remove from history after pressing delete 2021-03-17 15:20:12 +04:00
x-yl
8b89b27fb0 Misc. fixes 2021-03-17 10:57:56 +04:00
x-yl
b56c976fa0 code cleanup 2021-03-17 10:26:22 +04:00
x-yl
08889fdc60 docs 2021-03-17 10:20:21 +04:00
x-yl
e8d657e81c free storage after images leave clipboard 2021-03-17 09:38:03 +04:00
x-yl
bfcea8b718 Make pins persistent 2021-03-16 18:58:14 +04:00
x-yl
7f07686b6c added proper mime type support to content provider 2021-03-16 16:38:01 +04:00
x-yl
e4ecc63b9d Added an abstraction around ClipData 2021-03-15 15:12:30 +04:00
x-yl
aacb33bd5d fixed issue when floris clipboard is disabled 2021-03-13 20:46:27 +04:00
x-yl
a0aa446988 Change back button 2021-03-13 18:06:10 +04:00
x-yl
fe086ed6d8 removed some debug logging 2021-03-13 17:39:11 +04:00
x-yl
64ddd0f421 fixed a stupid bug somehow 2021-03-13 17:35:35 +04:00
x-yl
40fe72e33c fix a few bugs 2021-03-13 14:55:58 +04:00
x-yl
b229970ec3 cleanup and documentation 2021-03-13 13:04:34 +04:00
x-yl
ec32c211f1 added delete and paste. pretty much feature complete now. 2021-03-12 23:39:23 +04:00
x-yl
e66b8a052a Pin/unpin support 2021-03-12 22:18:40 +04:00
x-yl
4a22c2698c added more ways to open clipboard context, fixed popups, refactored some code 2021-03-12 21:50:24 +04:00
x-yl
ae95bbd7c4 Added a mock popup 2021-03-11 18:03:08 +04:00
x-yl
0bdeeaa340 VERY work in progress 2021-03-11 10:24:40 +04:00
x-yl
92a885a34c Little bit of preference stuff 2021-03-11 10:24:35 +04:00
x-yl
bc2f03a920 light refactoring, some theme stuff 2021-03-11 10:24:26 +04:00
x-yl
f60827b634 small theme fix 2021-03-11 10:23:59 +04:00
x-yl
dcf81b27a0 Fixed animations, added image support, some documentation 2021-03-11 10:23:59 +04:00
x-yl
0d8601cb15 Text-only clipboard history implemented 2021-03-11 10:23:59 +04:00
x-yl
ecf3c6bf27 All clipboard actions now use FlorisClipboardManager. Added support for commiting non-text content. Added simple clipboard history layout. 2021-03-11 10:23:46 +04:00
113 changed files with 3727 additions and 448 deletions

View File

@@ -1,14 +1,15 @@
<img align="left" width="80" height="80"
src="fastlane/metadata/android/en-US/images/icon.png" alt="App icon">
# FlorisBoard [![Release](https://img.shields.io/github/v/release/florisboard/florisboard)](https://github.com/florisboard/florisboard/releases) [![Crowdin](https://badges.crowdin.net/florisboard/localized.svg)](https://crowdin.florisboard.patrickgold.dev) ![FlorisBoard CI](https://github.com/florisboard/florisboard/workflows/FlorisBoard%20CI/badge.svg?event=push)
# FlorisBoard [![Crowdin](https://badges.crowdin.net/florisboard/localized.svg)](https://crowdin.florisboard.patrickgold.dev) ![FlorisBoard CI](https://github.com/florisboard/florisboard/workflows/FlorisBoard%20CI/badge.svg?event=push)
**FlorisBoard** is a free and open-source keyboard for Android 6.0+
devices. It aims at being modern, user-friendly and customizable while
fully respecting your privacy. Currently in alpha/early-beta state.
fully respecting your privacy. Currently in early-beta state.
## Public Alpha Test Programme
Wanna try it out on your device? Use one of the following options:
### Stable [![Latest stable release](https://img.shields.io/github/v/release/florisboard/florisboard)](https://github.com/florisboard/florisboard/releases/latest)
Releases on this track are in general stable and ready for everyday use, except for features marked as experimental. Use one of the following options to receive FlorisBoard's stable releases:
_A. Get it on F-Droid_:
@@ -36,6 +37,16 @@ for and download FlorisBoard without prior joining the alpha group.
_C. Use the APK provided in the release section of this repo_
### Beta [![Latest beta release](https://img.shields.io/github/v/release/florisboard/florisboard?include_prereleases)](https://github.com/florisboard/florisboard/releases)
Releases on this track are also in general stable and should be ready for everyday use, though crashes and bugs are more likely to occur. Use releases from this track if you want to get new features faster and give feedback for brand-new stuff. Options to get beta releases:
_A. IzzySoft's repo for F-Droid_:
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="64" alt="IzzySoft repo badge">](https://apt.izzysoft.de/fdroid/index/apk/dev.patrickgold.florisboard.beta)
_B. Use the APK provided in the release section of this repo_
### Giving feedback
If you want to give feedback to FlorisBoard, there are several ways to
do so, as listed [here](CONTRIBUTING.md#giving-general-feedback).
@@ -63,7 +74,7 @@ milestones, please refer to the [Feature roadmap](#feature-roadmap).
### Layouts
* [x] Latin character layouts (QWERTY, QWERTZ, AZERTY, Swiss, Spanish, Norwegian, Swedish/Finnish, Icelandic, Danish,
Hungarian, Croatian, Polish, Romanian, Colemak, Dvorak, ...)
Hungarian, Croatian, Polish, Romanian, Colemak, Dvorak, Turkish-Q, Turkish-F, ...)
* [x] Non-latin character layouts (Arabic, Persian, Greek, Russian (JCUKEN))
* [x] Adapt to situation in app (password, url, text, etc. )
* [x] Special character layout(s)
@@ -86,6 +97,7 @@ milestones, please refer to the [Feature roadmap](#feature-roadmap).
### Other useful features
* [x] One-handed mode
* [x] Clipboard/cursor tools
* [x] Clipboard manager/history
* [x] Integrated number row / symbols in character layouts
* [x] Gesture support
* [x] Full integration in IME service list of Android (xml/method)

View File

@@ -1,6 +1,8 @@
plugins {
id("com.android.application") version "4.1.2"
kotlin("android") version "1.4.30"
kotlin("kapt") version "1.4.30"
}
android {
@@ -21,8 +23,8 @@ android {
applicationId = "dev.patrickgold.florisboard"
minSdkVersion(23)
targetSdkVersion(30)
versionCode(28)
versionName("0.3.9")
versionCode(32)
versionName("0.3.10")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -44,7 +46,7 @@ android {
create("beta") // Needed because by default the "beta" BuildType does not exist
named("beta").configure {
applicationIdSuffix = ".beta"
versionNameSuffix = "-beta"
versionNameSuffix = "-beta04"
proguardFiles.add(getDefaultProguardFile("proguard-android-optimize.txt"))
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_beta")
@@ -72,6 +74,7 @@ android {
}
}
dependencies {
implementation("androidx.activity", "activity-ktx", "1.2.1")
implementation("androidx.appcompat", "appcompat", "1.2.0")
@@ -88,6 +91,8 @@ dependencies {
implementation("com.jaredrummler", "colorpicker", "1.1.0")
implementation("com.jakewharton.timber", "timber", "4.7.1")
implementation("com.nambimobile.widgets", "expandable-fab", "1.0.2")
implementation("androidx.room", "room-runtime", "2.2.6")
kapt("androidx.room", "room-compiler","2.2.6")
testImplementation("junit", "junit", "4.13.1")
testImplementation("org.mockito", "mockito-inline", "3.7.7")

View File

@@ -111,6 +111,14 @@
android:label="@string/crash_dialog__title"
android:theme="@style/CrashDialogTheme"/>
<provider
android:name="dev.patrickgold.florisboard.ime.clip.provider.FlorisContentProvider"
android:authorities="dev.patrickgold.florisboard.provider.clip"
android:grantUriPermissions="true"
android:exported="false">
</provider>
</application>
</manifest>

View File

@@ -4,31 +4,33 @@
"qwerty": "QWERTY",
"qwertz": "QWERTZ",
"azerty": "AZERTY",
"arabic": "Arabic",
"bepo": "BÉPO",
"bulgarian_bds": "Bulgarian (BDS)",
"bulgarian_phonetic": "Bulgarian (Phonetic)",
"spanish": "Spanish (QWERTY)",
"norwegian": "Norwegian (QWERTY)",
"swedish_finnish": "Swedish/Finnish (QWERTY)",
"canadian_french": "Canadian French (QWERTY)",
"colemak": "Colemak",
"danish": "Danish (QWERTY)",
"dvorak": "Dvorak",
"esperanto": "Esperanto",
"esperanto_with_hx": "Esperanto with 'ĥ'",
"greek": "Ελληνικά",
"hebrew": "עברית",
"hungarian": "Hungarian (QWERTZ)",
"icelandic": "Icelandic (QWERTY)",
"kurdish": "کوردی",
"norwegian": "Norwegian (QWERTY)",
"persian": "Persian",
"jcuken_russian": "Russian (JCUKEN)",
"serbian_latin": "Serbian (QWERTZ)",
"serbian_cyrillic": "Serbian (ЉЊЕРТЗ)",
"spanish": "Spanish (QWERTY)",
"swedish_finnish": "Swedish/Finnish (QWERTY)",
"swiss_german": "Swiss German (QWERTZ)",
"swiss_french": "Swiss French (QWERTZ)",
"swiss_italian": "Swiss Italian (QWERTZ)",
"hungarian": "Hungarian (QWERTZ)",
"persian": "Persian",
"arabic": "Arabic",
"esperanto": "Esperanto",
"esperanto_with_hx": "Esperanto with 'ĥ'",
"colemak": "Colemak",
"dvorak": "Dvorak",
"jcuken_russian": "Russian (JCUKEN)",
"canadian_french": "Canadian French (QWERTY)",
"greek": "Ελληνικά",
"hebrew": "עברית",
"serbian_latin": "Serbian (QWERTZ)",
"serbian_cyrillic": "Serbian (ЉЊЕРТЗ)",
"kurdish": "کوردی"
"turkish_q": "Turkish-Q",
"turkish_f": "Turkish-F"
},
"defaultSubtypes": [
{

View File

@@ -7,7 +7,8 @@
"~enter": {
"main": { "code": -213, "label": "switch_to_media_context", "type": "system_gui" },
"relevant": [
{ "code": -216, "label": "toggle_one_handed_mode_right", "type": "system_gui" }
{ "code": -216, "label": "toggle_one_handed_mode_right", "type": "system_gui" },
{ "code": -214, "label": "switch_to_clipboard_context", "type": "system_gui"}
]
},
"~left": {

View File

@@ -21,9 +21,7 @@
]
},
"z": {
"relevant": [
{ "code": 382, "label": "ž" }
]
"main": { "code": 382, "label": "ž" }
},
"~right": {
"main": { "code": 44, "label": "," },
@@ -50,9 +48,9 @@
"~right": {
"main": { "code": -255, "label": ".com" },
"relevant": [
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".eu" },
{ "code": -255, "label": ".rs" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,46 +1,100 @@
{
"type": "characters/extended_popups",
"name": "tr",
"authors": [ "kisekinopureya" ],
"authors": [ "kisekinopureya", "patrickgold" ],
"mapping": {
"all": {
"a": {
"relevant": [
{ "code": 226, "label": "â" }
{ "code": 226, "label": "â" },
{ "code": 228, "label": "ä" },
{ "code": 225, "label": "á" }
]
},
"c": {
"main": { "code": 231, "label": "ç" },
"relevant": [
{ "code": 231, "label": "ç" }
{ "code": 269, "label": "č" },
{ "code": 263, "label": "ć" }
]
},
"e": {
"relevant": [
{ "code": 233, "label": "é" },
{ "code": 601, "label": "ə" },
{ "code": 234, "label": "ê" }
]
},
"g": {
"relevant": [
{ "code": 287, "label": "ğ" }
]
"main": { "code": 287, "label": "ğ" }
},
"i": {
"main": { "code": 305, "label": "ı" },
"relevant": [
{ "code": 303, "label": "į" },
{ "code": 236, "label": "ì" },
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 238, "label": "î" },
{ "code": 305, "label": "ı" }
{ "code": 239, "label": "ï" }
]
},
"ı": {
"main": { "code": 105, "label": "i" },
"relevant": [
{ "code": 303, "label": "į" },
{ "code": 236, "label": "ì" },
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 238, "label": "î" },
{ "code": 239, "label": "ï" }
]
},
"n": {
"relevant": [
{ "code": 328, "label": "ň" },
{ "code": 241, "label": "ñ" }
]
},
"o": {
"main": { "code": 246, "label": "ö" },
"relevant": [
{ "code": 246, "label": "ö" }
{ "code": 333, "label": "ō" },
{ "code": 248, "label": "ø" },
{ "code": 243, "label": "ó" },
{ "code": 245, "label": "õ" },
{ "code": 242, "label": "ò" },
{ "code": 339, "label": "œ" },
{ "code": 244, "label": "ô" }
]
},
"s": {
"main": { "code": 351, "label": "ş" },
"relevant": [
{ "code": 351, "label": "ş" }
{ "code": 347, "label": "ś" },
{ "code": 223, "label": "ß" },
{ "code": 353, "label": "š" }
]
},
"u": {
"main": { "code": 252, "label": "ü" },
"relevant": [
{ "code": 252, "label": "ü" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 250, "label": "ú" },
{ "code": 251, "label": "û" }
]
},
"y": {
"relevant": [
{ "code": 253, "label": "ý" }
]
},
"z": {
"relevant": [
{ "code": 382, "label": "ž" }
]
},
"~right": {
"main": { "code": 44, "label": "," },
"relevant": [
@@ -67,9 +121,9 @@
"main": { "code": -255, "label": ".com" },
"relevant": [
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".tr" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -0,0 +1,46 @@
{
"type": "characters",
"name": "turkish_f",
"authors": [ "patrickgold" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 102, "label": "f" },
{ "code": 103, "label": "g" },
{ "code": 287, "label": "ğ" },
{ "code": 305, "label": "ı" },
{ "code": 111, "label": "o" },
{ "code": 100, "label": "d" },
{ "code": 114, "label": "r" },
{ "code": 110, "label": "n" },
{ "code": 104, "label": "h" },
{ "code": 112, "label": "p" },
{ "code": 113, "label": "q" },
{ "code": 119, "label": "w" }
],
[
{ "code": 117, "label": "u" },
{ "code": 105, "label": "i" },
{ "code": 101, "label": "e" },
{ "code": 97, "label": "a" },
{ "code": 252, "label": "ü" },
{ "code": 116, "label": "t" },
{ "code": 107, "label": "k" },
{ "code": 109, "label": "m" },
{ "code": 108, "label": "l" },
{ "code": 121, "label": "y" },
{ "code": 351, "label": "ş" }
],
[
{ "code": 106, "label": "j" },
{ "code": 246, "label": "ö" },
{ "code": 118, "label": "v" },
{ "code": 99, "label": "c" },
{ "code": 231, "label": "ç" },
{ "code": 122, "label": "z" },
{ "code": 115, "label": "s" },
{ "code": 98, "label": "b" },
{ "code": 120, "label": "x" }
]
]
}

View File

@@ -0,0 +1,46 @@
{
"type": "characters",
"name": "turkish_q",
"authors": [ "patrickgold" ],
"direction": "ltr",
"arrangement": [
[
{ "code": 113, "label": "q" },
{ "code": 119, "label": "w" },
{ "code": 101, "label": "e" },
{ "code": 114, "label": "r" },
{ "code": 116, "label": "t" },
{ "code": 121, "label": "y" },
{ "code": 117, "label": "u" },
{ "code": 305, "label": "ı" },
{ "code": 111, "label": "o" },
{ "code": 112, "label": "p" },
{ "code": 287, "label": "ğ" },
{ "code": 252, "label": "ü" }
],
[
{ "code": 97, "label": "a" },
{ "code": 115, "label": "s" },
{ "code": 100, "label": "d" },
{ "code": 102, "label": "f" },
{ "code": 103, "label": "g" },
{ "code": 104, "label": "h" },
{ "code": 106, "label": "j" },
{ "code": 107, "label": "k" },
{ "code": 108, "label": "l" },
{ "code": 351, "label": "ş" },
{ "code": 105, "label": "i" }
],
[
{ "code": 122, "label": "z" },
{ "code": 120, "label": "x" },
{ "code": 99, "label": "c" },
{ "code": 118, "label": "v" },
{ "code": 98, "label": "b" },
{ "code": 110, "label": "n" },
{ "code": 109, "label": "m" },
{ "code": 246, "label": "ö" },
{ "code": 231, "label": "ç" }
]
]
}

View File

@@ -10,7 +10,8 @@
{ "code": -20, "label": "arrow_left", "type": "navigation" },
{ "code": -21, "label": "arrow_right", "type": "navigation" },
{ "code": -131, "label": "clipboard_cut", "type": "enter_editing" },
{ "code": -132, "label": "clipboard_paste", "type": "enter_editing" }
{ "code": -132, "label": "clipboard_paste", "type": "enter_editing" },
{ "code": -214, "label": "switch_to_clipboard_context", "type": "system_gui"}
]
]
}

View File

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

View File

@@ -0,0 +1,114 @@
package dev.patrickgold.florisboard.ime.clip
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.clip.provider.ItemType
import dev.patrickgold.florisboard.ime.core.FlorisBoard
class ClipboardHistoryItemAdapter(
private val dataSet: ArrayDeque<FlorisClipboardManager.TimedClipData>,
private val pins: ArrayDeque<ClipboardItem>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
class ClipboardHistoryTextViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.clipboard_history_item_text)
}
class ClipboardHistoryImageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val imgView: ImageView = view.findViewById(R.id.clipboard_history_item_img)
}
companion object {
private const val MAX_SIZE: Int = 256
}
override fun getItemViewType(position: Int): Int {
return if (position < pins.size) {
// is a pin
pins[position].type.value
}else {
// regular history item
dataSet[position - pins.size].data.type.value
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
// Create a new view, which defines the UI of the list item
val vh = when (viewType) {
ItemType.IMAGE.value -> {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.clipboard_history_item_image, viewGroup, false)
ClipboardHistoryImageViewHolder(view)
}
ItemType.TEXT.value -> {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.clipboard_history_item_text, viewGroup, false)
ClipboardHistoryTextViewHolder(view)
}
else -> null
}!!
val clipboardInputManager = ClipboardInputManager.getInstance()
(vh.itemView as ClipboardHistoryItemView).keyboardView = clipboardInputManager.getClipboardHistoryView()
return vh
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
when (viewHolder) {
is ClipboardHistoryTextViewHolder -> {
var text = if (position < pins.size) {
(viewHolder.itemView as ClipboardHistoryItemView).setPinned()
pins[position].text
}else {
(viewHolder.itemView as ClipboardHistoryItemView).setUnpinned()
dataSet[position - pins.size].data.text
}
if (text!!.length > MAX_SIZE) {
text = text.subSequence(0 until MAX_SIZE).toString() + "..."
}
viewHolder.textView.text = text
}
is ClipboardHistoryImageViewHolder -> {
val uri = if (position < pins.size) {
(viewHolder.itemView as ClipboardHistoryItemView).setPinned()
pins[position].uri
}else {
(viewHolder.itemView as ClipboardHistoryItemView).setUnpinned()
dataSet[position - pins.size].data.uri
}
viewHolder.imgView.clipToOutline = true
viewHolder.imgView.visibility = GONE
// For very large images, this can take a bit
FlorisClipboardManager.getInstance().executor.execute {
val resolver = FlorisBoard.getInstance().context.contentResolver
val inputStream = resolver.openInputStream(uri!!)
val drawable = Drawable.createFromStream(inputStream, "clipboard URI")
viewHolder.itemView.post {
viewHolder.imgView.setImageDrawable(drawable)
viewHolder.imgView.visibility = VISIBLE
}
}
}
}
}
override fun getItemCount() = pins.size + dataSet.size
}

View File

@@ -0,0 +1,86 @@
package dev.patrickgold.florisboard.ime.clip
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.constraintlayout.widget.ConstraintLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
class ClipboardHistoryItemView: ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
lateinit var keyboardView: ClipboardHistoryView
constructor(context: Context) : this(context, null as AttributeSet?)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
private var popupManager: ClipboardPopupManager? = null
override fun onAttachedToWindow() {
super.onAttachedToWindow()
popupManager = ClipboardPopupManager(keyboardView, FlorisBoard.getInstance().popupLayerView, this)
setOnClickListener{
onClickItem()
}
setOnLongClickListener{
onLongClickItem()
}
val themeManager = ThemeManager.default()
themeManager.registerOnThemeUpdatedListener(this)
}
override fun onThemeUpdated(theme: Theme) {
background.setTint(theme.getAttr(Theme.Attr.KEY_BACKGROUND).toSolidColor().color)
val pin = findViewById<ImageView>(R.id.clipboard_pin).drawable
pin?.setTint(theme.getAttr(Theme.Attr.KEY_FOREGROUND).toSolidColor().color)
}
private fun onLongClickItem() : Boolean {
popupManager?.show(this)
return true
}
private fun onClickItem(){
val position = ClipboardInputManager.getInstance().getPositionOfView(this)
val instance = FlorisClipboardManager.getInstance()
val canPaste = instance.canBePasted(instance.peekHistoryOrPin(position))
if (canPaste) {
instance.pasteItem(position)
}else {
Toast.makeText(context, context.getString(R.string.clip__cant_paste), Toast.LENGTH_SHORT).show()
}
}
fun setPinned() {
val view = findViewById<TextView>(R.id.clipboard_history_item_text)
view?.run {
val params = layoutParams as LayoutParams
params.marginEnd = resources.getDimensionPixelSize(R.dimen.clipboard_text_item_pin_margin)
layoutParams = params
}
findViewById<ImageView>(R.id.clipboard_pin).visibility = VISIBLE
invalidate()
val themeManager = ThemeManager.default()
onThemeUpdated(themeManager.activeTheme)
}
fun setUnpinned(){
val view = findViewById<TextView>(R.id.clipboard_history_item_text)
// if text view, also update margin.
view?.run {
val params = layoutParams as LayoutParams
params.marginEnd = 0
layoutParams = params
invalidate()
}
findViewById<ImageView>(R.id.clipboard_pin).visibility = INVISIBLE
}
}

View File

@@ -0,0 +1,71 @@
package dev.patrickgold.florisboard.ime.clip
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import kotlin.math.roundToInt
class ClipboardHistoryView : LinearLayout, FlorisBoard.EventListener,
ThemeManager.OnThemeUpdatedListener {
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
private val themeManager: ThemeManager = ThemeManager.default()
var backButton: ImageButton? = null
private set
var clipText: TextView? = null
private set
var clipboardBar: LinearLayout? = null
private set
private var clipboardHistory: RecyclerView? = null
private var clearAll: ImageButton? = null
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
florisboard?.addEventListener(this)
themeManager.registerOnThemeUpdatedListener(this)
backButton = findViewById(R.id.back_to_keyboard_button)
clipText = findViewById(R.id.clipboard_text)
clipboardBar = findViewById(R.id.clipboard_bar)
clipboardHistory = findViewById(R.id.clipboard_history_items)
clearAll = findViewById(R.id.clear_clipboard_history)
onApplyThemeAttributes()
// lord alone knows why it doesn't work without this..
onThemeUpdated(themeManager.activeTheme)
}
override fun onDetachedFromWindow() {
themeManager.unregisterOnThemeUpdatedListener(this)
florisboard?.removeEventListener(this)
super.onDetachedFromWindow()
}
override fun onThemeUpdated(theme: Theme) {
val fgColor = theme.getAttr(Theme.Attr.KEY_FOREGROUND).toSolidColor().color
clipText?.setTextColor(fgColor)
backButton?.drawable?.setTint(fgColor)
clearAll?.setColorFilter(fgColor)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val height = florisboard?.inputView?.desiredMediaKeyboardViewHeight ?: 0.0f
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height.roundToInt(), MeasureSpec.EXACTLY))
}
}

View File

@@ -0,0 +1,218 @@
package dev.patrickgold.florisboard.ime.clip
import android.annotation.SuppressLint
import android.os.Handler
import android.os.Looper
import android.view.MotionEvent
import android.view.View
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
import dev.patrickgold.florisboard.ime.core.InputView
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.key.KeyData
import kotlinx.coroutines.*
import kotlin.math.pow
/**
* Handles the clipboard view and allows for communication between UI and logic.
*/
class ClipboardInputManager private constructor() : CoroutineScope by MainScope(),
FlorisBoard.EventListener{
private val florisboard = FlorisBoard.getInstance()
private var repeatedKeyPressHandler: Handler? = null
private var recyclerView: RecyclerView? = null
private var adapter: ClipboardHistoryItemAdapter? = null
companion object {
private var instance: ClipboardInputManager? = null
@Synchronized
fun getInstance(): ClipboardInputManager {
if (instance == null) {
instance = ClipboardInputManager()
}
return instance!!
}
}
init {
florisboard.addEventListener(this)
}
override fun onCreateInputView() {
super.onCreateInputView()
repeatedKeyPressHandler = Handler(florisboard.context.mainLooper)
}
/**
* Called when a new input view has been registered. Used to initialize all media-relevant
* views and layouts.
*/
@SuppressLint("ClickableViewAccessibility")
override fun onRegisterInputView(inputView: InputView) {
launch(Dispatchers.Default) {
inputView.findViewById<ImageButton>(R.id.back_to_keyboard_button)
.setOnTouchListener { view, event -> onButtonPressEvent(view, event) }
inputView.findViewById<ImageButton>(R.id.clear_clipboard_history)
.setOnTouchListener { view, event -> onButtonPressEvent(view, event) }
recyclerView = inputView.findViewById(R.id.clipboard_history_items)
if (BuildConfig.DEBUG && adapter == null) {
error("initClipboard() not called")
}
recyclerView!!.adapter = adapter
val manager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
recyclerView!!.layoutManager = manager
}
}
/**
* Clean-up of resources and stopping all coroutines.
*/
override fun onDestroy() {
cancel()
instance = null
}
/**
* Returns a reference to the [ClipboardHistoryView]
*/
fun getClipboardHistoryView() : ClipboardHistoryView{
return FlorisBoard.getInstance().inputView?.mainViewFlipper?.getChildAt(2) as ClipboardHistoryView
}
/**
* Returns the adapter position of the view, i.e the position that the item is displayed at (including pins and
* history items).
*
* @param view The ClipboardHistoryItemView whose position is to be determined.
* @return The adapter position of the view
*/
fun getPositionOfView(view: View): Int {
return recyclerView?.getChildLayoutPosition(view)!!
}
/**
* Notify adapter that an item was inserted.
*
* @param position The position the item was inserted at
*/
fun notifyItemInserted(position: Int) = adapter?.notifyItemInserted(position)
/**
* Notify adapter that an item was removed
* @param position The position the item was removed from
*/
fun notifyItemRemoved(position: Int) = adapter?.notifyItemRemoved(position)
/**
* Notify adapter that an item range was removed.
* @param start The index the range starts at (inclusive)
* @param numberOfItems The number of items removed
*/
fun notifyItemRangeRemoved(start: Int, numberOfItems: Int) = adapter?.notifyItemRangeRemoved(start, numberOfItems)
/**
* Notify adapter that an item was moved
* @param from The original position
* @param to The final position
*/
fun notifyItemMoved(from: Int, to: Int) = adapter?.notifyItemMoved(from, to)
/**
* Notify adapter that an item was changed.
*
* @param i The position of the item
*/
fun notifyItemChanged(i: Int) = adapter?.notifyItemChanged(i)
/**
* Handles clicks on the back to keyboard button.
*/
private fun onButtonPressEvent(view: View, event: MotionEvent?): Boolean {
event ?: return false
val data = when (view.id) {
R.id.back_to_keyboard_button -> KeyData(code = KeyCode.SWITCH_TO_TEXT_CONTEXT)
R.id.clear_clipboard_history -> KeyData(code = KeyCode.CLEAR_CLIPBOARD_HISTORY)
else -> null
}!!
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
florisboard.keyPressVibrate()
florisboard.keyPressSound(data)
florisboard.textInputManager.inputEventDispatcher.send(InputKeyEvent.down(data))
}
MotionEvent.ACTION_UP -> {
florisboard.textInputManager.inputEventDispatcher.send(InputKeyEvent.up(data))
}
MotionEvent.ACTION_CANCEL -> {
florisboard.textInputManager.inputEventDispatcher.send(InputKeyEvent.cancel(data))
}
}
// MUST return false here so the background selector for showing a transparent bg works
return false
}
/**
* [recyclerView] will be linked to [dataSet] and [pins] when initialized.
*
* @param dataSet the data set to link to
* @param pins The pins to link to
*/
fun initClipboard(dataSet: ArrayDeque<FlorisClipboardManager.TimedClipData>, pins: ArrayDeque<ClipboardItem>) {
this.adapter = ClipboardHistoryItemAdapter(dataSet = dataSet, pins= pins)
}
/**
* Plays an animation of all items moving off the the clipboard from the top.
*
* @param start The index to start at (to ignore pins)
* @param size The size of the clipboard
* @return The time in millis till the last animation will complete.
*/
fun clearClipboardWithAnimation(start: Int, size: Int): Long {
// list of views to animate
val views = arrayListOf<View>()
for(i in 0 until size){
recyclerView?.findViewHolderForLayoutPosition(i + start)?.let {
views.add(it.itemView)
}
}
// animate the views
var delay = 1L
for (view in views) {
delay += (10 * delay.toDouble().pow(0.1)).toLong()
val an = view.animate().translationX(1500f)
an.startDelay = delay
an.duration = 250
}
// a little while later we reset the views so they can be reused.
Handler(Looper.getMainLooper()).postDelayed({
for (view in views) {
view.translationX = 0f
}
}, 450 + delay)
return 280 + delay
}
}

View File

@@ -0,0 +1,127 @@
package dev.patrickgold.florisboard.ime.clip
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.LinearLayout
import android.widget.Space
import android.widget.TextView
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.popup.PopupLayerView
import kotlin.math.max
class ClipboardPopupManager(private val keyboardView: ClipboardHistoryView,
private val popupLayerView: PopupLayerView?,
private val clipboardHistoryItem: ClipboardHistoryItemView) {
private val popupView: ClipboardPopupView = LayoutInflater.from(keyboardView.context).inflate(R.layout.clip_popup_layout, null) as ClipboardPopupView
private var width = 0
private var height = 0
private var xOffset = 0
private var yOffset = 0
init {
popupLayerView?.addView(popupView)
}
private fun pinButtonListener() {
val pos = ClipboardInputManager.getInstance().getPositionOfView(clipboardHistoryItem)
val pinned = FlorisClipboardManager.getInstance().isPinned(pos)
if (pinned) {
FlorisClipboardManager.getInstance().unpinClip(pos)
hide()
} else {
FlorisClipboardManager.getInstance().pinClip(pos)
hide()
}
}
/**
* Show a popup.
*/
fun show(view: ClipboardHistoryItemView) {
val pinButton = popupView.findViewById<LinearLayout>(R.id.pin_clip_item)
pinButton.setOnClickListener {
pinButtonListener()
}
val pos = ClipboardInputManager.getInstance().getPositionOfView(clipboardHistoryItem)
val pinned = FlorisClipboardManager.getInstance().isPinned(pos)
if (pinned) {
pinButton.findViewById<TextView>(R.id.pin_clip_item_text).text = view.context.getString(R.string.clip__unpin_item)
}
val delete = popupView.findViewById<LinearLayout>(R.id.remove_from_history)
delete.setOnClickListener {
FlorisClipboardManager.getInstance().removeClip(pos)
hide()
}
val clipboardManager = FlorisClipboardManager.getInstance()
val clipItem = clipboardManager.peekHistoryOrPin(pos)
val pasteShouldBeEnabled = FlorisClipboardManager.getInstance().canBePasted(clipItem)
// the clipboard item has any of the supported mime types of the editor OR is plain text.
val paste = popupView.findViewById<LinearLayout>(R.id.paste_clip_item)
if (pasteShouldBeEnabled) {
paste.setOnClickListener {
FlorisClipboardManager.getInstance().pasteItem(pos)
hide()
}
popupView.findViewById<Space>(R.id.paste_clip_item_space).visibility = VISIBLE
paste.visibility = VISIBLE
}else {
popupView.findViewById<Space>(R.id.paste_clip_item_space).visibility = GONE
paste.visibility = GONE
}
FlorisBoard.getInstance().isClipboardContextMenuShown = true
popupLayerView?.clipboardPopupManager = this
popupLayerView?.intercept = popupView
calc(view)
popupView.properties.let {
it.width = this.width
it.height = this.height
it.xOffset = this.xOffset
it.yOffset = this.yOffset
}
popupView.show(keyboardView)
}
/**
* Calculate sizes of popup.
*/
private fun calc(view: ClipboardHistoryItemView) {
val widthMeasureSpec: Int = View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.AT_MOST)
val heightMeasureSpec: Int = View.MeasureSpec.makeMeasureSpec(100000, View.MeasureSpec.AT_MOST)
popupView.invalidate()
popupView.measure(widthMeasureSpec, heightMeasureSpec)
width = view.width * 4 / 5
height = popupView.measuredHeight
xOffset = view.x.toInt() + (view.width - width) / 2
// y offset is either where the top of the item is OR if the top is off screen, the top of the keyboard.
yOffset = max(view.y.toInt() - keyboardView.height - height / 2 - 20, keyboardView.y.toInt() - keyboardView.height - height / 2 - 20)
}
/**
* Hides a popup.
*/
fun hide() {
popupView.hide()
popupLayerView?.intercept = null
popupLayerView?.clipboardPopupManager = null
FlorisBoard.getInstance().isClipboardContextMenuShown = false
popupView.apply {
visibility = GONE
}
}
}

View File

@@ -0,0 +1,130 @@
package dev.patrickgold.florisboard.ime.clip
import android.content.Context
import android.graphics.drawable.PaintDrawable
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.util.ViewLayoutUtils
class ClipboardPopupView: LinearLayout, ThemeManager.OnThemeUpdatedListener {
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
private var backgroundDrawable: PaintDrawable = PaintDrawable().apply {
setCornerRadius(ViewLayoutUtils.convertDpToPixel(6.0f, context))
}
private val themeManager: ThemeManager = ThemeManager.default()
val properties: Properties = Properties(
width = 0,
height = 0,
xOffset = 0,
yOffset = 0
)
private val isShowing: Boolean
get() = visibility == VISIBLE
init {
visibility = GONE
background = backgroundDrawable
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
themeManager.registerOnThemeUpdatedListener(this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
themeManager.unregisterOnThemeUpdatedListener(this)
}
override fun onThemeUpdated(theme: Theme) {
backgroundDrawable.apply {
setTint(theme.getAttr(Theme.Attr.POPUP_BACKGROUND).toSolidColor().color)
}
this.findViewById<ImageView>(R.id.pin_clip_item_icon).drawable.apply {
setTint(theme.getAttr(Theme.Attr.WINDOW_TEXT_COLOR).toSolidColor().color)
}
this.findViewById<ImageView>(R.id.remove_from_history_icon).drawable.apply {
setTint(theme.getAttr(Theme.Attr.WINDOW_TEXT_COLOR).toSolidColor().color)
}
this.findViewById<ImageView>(R.id.paste_clip_item_icon).drawable.apply {
setTint(theme.getAttr(Theme.Attr.WINDOW_TEXT_COLOR).toSolidColor().color)
}
if (isShowing) {
invalidate()
}
}
private fun applyProperties(anchor: View) {
val anchorCoords = IntArray(2)
anchor.getLocationInWindow(anchorCoords)
val anchorX = anchorCoords[0]
val anchorY = anchorCoords[1] + anchor.measuredHeight
when (val lp = layoutParams) {
is FrameLayout.LayoutParams -> lp.apply {
width = properties.width
height = properties.height
setMargins(
anchorX + properties.xOffset,
anchorY + properties.yOffset,
0,
0
)
}
else -> {
layoutParams = FrameLayout.LayoutParams(properties.width, properties.height).apply {
setMargins(
anchorX + properties.xOffset,
anchorY + properties.yOffset,
0,
0
)
}
}
}
if (isShowing) {
requestLayout()
invalidate()
}
}
fun show(anchor: View) {
applyProperties(anchor)
visibility = VISIBLE
requestLayout()
invalidate()
}
fun hide() {
visibility = GONE
requestLayout()
invalidate()
}
data class Properties(
var width: Int,
var height: Int,
var xOffset: Int,
var yOffset: Int
)
}

View File

@@ -0,0 +1,405 @@
package dev.patrickgold.florisboard.ime.clip
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
import android.os.Handler
import android.os.Looper
import dev.patrickgold.florisboard.ime.clip.provider.*
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.PrefHelper
import dev.patrickgold.florisboard.util.cancelAll
import dev.patrickgold.florisboard.util.postAtScheduledRate
import timber.log.Timber
import java.io.Closeable
import java.util.*
import java.util.concurrent.ExecutorService
import kotlin.collections.ArrayDeque
/**
* [FlorisClipboardManager] manages the clipboard and clipboard history.
*
* Also just going to document how all the classes here work.
*
* [FlorisClipboardManager] handles storage and retrieval of clipboard items. All manipulation of the
* clipboard goes through here.
*
* [ClipboardInputManager] handles the input view and allows for communication between UI and logic
*
* [ClipboardHistoryView] is the view representing the clipboard context. Only does some theme stuff.
*
* [ClipboardHistoryItemView] is the view representing an item in the clipboard history (either image or text). Only
* does UI stuff.
*
* [ClipboardHistoryItemAdapter] is the recyclerview adapter that backs the clipboard history.
*
* [ClipboardPopupManager] handles the popups for each [ClipboardHistoryItemView] (each item has its own popup manager)
*
* [ClipboardPopupView] is the view representing a popup displayed when long pressing on a clipboard history item.
*/
class FlorisClipboardManager private constructor() : ClipboardManager.OnPrimaryClipChangedListener, Closeable {
private lateinit var pinsDao: PinnedClipboardItemDao
lateinit var executor: ExecutorService
// Using ArrayDeque because it's "technically" the correct data structure (I think).
// Newest stored first, oldest stored last.
private var history: ArrayDeque<TimedClipData> = ArrayDeque()
private var pins: ArrayDeque<ClipboardItem> = ArrayDeque()
private var current: ClipboardItem? = null
private var onPrimaryClipChangedListeners: ArrayList<OnPrimaryClipChangedListener> = arrayListOf()
private lateinit var systemClipboardManager: ClipboardManager
private lateinit var handler: Handler
private lateinit var prefHelper: PrefHelper
data class TimedClipData(val data: ClipboardItem, val timeUTC: Long)
interface OnPrimaryClipChangedListener {
fun onPrimaryClipChanged()
}
companion object {
private var instance: FlorisClipboardManager? = null
// 1 minute
private const val INTERVAL = 60 * 1000L
@Synchronized
fun getInstance(): FlorisClipboardManager {
if (instance == null) {
instance = FlorisClipboardManager()
}
return instance!!
}
@Synchronized
fun getInstanceOrNull(): FlorisClipboardManager? = instance
/**
* Taken from ClipboardDescription.java from the AOSP
*
* Helper to compare two MIME types, where one may be a pattern.
* @param concreteType A fully-specified MIME type.
* @param desiredType A desired MIME type that may be a pattern such as * / *.
* @return Returns true if the two MIME types match.
*/
fun compareMimeTypes(concreteType: String, desiredType: String): Boolean {
val typeLength = desiredType.length
if (typeLength == 3 && desiredType == "*/*") {
return true
}
val slashpos = desiredType.indexOf('/')
if (slashpos > 0) {
if (typeLength == slashpos + 2 && desiredType[slashpos + 1] == '*') {
if (desiredType.regionMatches(0, concreteType, 0, slashpos + 1)) {
return true
}
} else if (desiredType == concreteType) {
return true
}
}
return false
}
}
/**
* Adds a new item to the clipboard history (if enabled).
*/
fun updateHistory(newData: ClipboardItem) {
val clipboardPrefs = prefHelper.clipboard
if (clipboardPrefs.enableHistory) {
if (clipboardPrefs.limitHistorySize) {
var numRemoved = 0
while (history.size >= clipboardPrefs.maxHistorySize) {
numRemoved += 1
history.removeLast().data.close()
}
ClipboardInputManager.getInstance().notifyItemRangeRemoved(history.size, numRemoved)
}
val timed = TimedClipData(newData, System.currentTimeMillis())
history.addFirst(timed)
ClipboardInputManager.getInstance().notifyItemInserted(pins.size)
}
}
/**
* Used so that [onPrimaryClipChanged] knows whether it was called by [changeCurrent] (and hence shouldn't update
* history)
*/
private var shouldUpdateHistory = true
/**
* Changes current clipboard item. WITHOUT updating the history.
*/
fun changeCurrent(newData: ClipboardItem, closePrevious: Boolean) {
if (prefHelper.clipboard.enableInternal) {
if (closePrevious) current?.close()
current = newData
val isEqual = when (newData.type) {
ItemType.TEXT -> newData.text == systemClipboardManager.primaryClip?.getItemAt(0)?.text
ItemType.IMAGE -> newData.uri == systemClipboardManager.primaryClip?.getItemAt(0)?.uri
}
if (prefHelper.clipboard.syncToSystem && !isEqual)
systemClipboardManager.setPrimaryClip(newData.toClipData())
} else {
shouldUpdateHistory = false
systemClipboardManager.setPrimaryClip(newData.toClipData())
}
onPrimaryClipChangedListeners.forEach { it.onPrimaryClipChanged() }
}
/**
* Change the current text on clipboard, update history (if enabled).
*
*/
fun addNewClip(newData: ClipboardItem) {
updateHistory(newData)
// If history is disabled, this new item will replace the old one and hence should be closed.
changeCurrent(newData, !prefHelper.clipboard.enableHistory)
}
/**
* Wraps some plaintext in a ClipData and calls [addNewClip]
*/
fun addNewPlaintext(newText: String) {
val newData = ClipboardItem(null, ItemType.TEXT, null, newText, ClipboardItem.TEXT_PLAIN)
addNewClip(newData)
}
val primaryClip: ClipboardItem?
get() = if (prefHelper.clipboard.enableInternal) {
current
} else {
systemClipboardManager.primaryClip?.let { ClipboardItem.fromClipData(it, false) }
}
fun peekHistory(index: Int): ClipboardItem? {
return history.getOrNull(index)?.data
}
fun addPrimaryClipChangedListener(listener: OnPrimaryClipChangedListener) {
onPrimaryClipChangedListeners.add(listener)
}
fun removePrimaryClipChangedListener(listener: OnPrimaryClipChangedListener) {
onPrimaryClipChangedListeners.remove(listener)
}
/**
* Called by system clipboard when the contents are changed
*/
override fun onPrimaryClipChanged() {
// Run on async thread to avoid blocking.
if (systemClipboardManager.primaryClip?.getItemAt(0)?.text == null &&
systemClipboardManager.primaryClip?.getItemAt(0)?.uri == null) {
return
}
val isEqual = when (primaryClip?.type) {
ItemType.TEXT -> primaryClip?.text == systemClipboardManager.primaryClip?.getItemAt(0)?.text
ItemType.IMAGE -> primaryClip?.uri == systemClipboardManager.primaryClip?.getItemAt(0)?.uri
null -> false
}
systemClipboardManager.primaryClip?.let {
if (prefHelper.clipboard.enableInternal) {
// In the event that the internal clipboard is enabled, sync to internal clipboard is enabled
// and the item is not already in internal clipboard, add it.
if (prefHelper.clipboard.syncToFloris && !isEqual) {
addNewClip(ClipboardItem.fromClipData(it, true))
}
} else if (prefHelper.clipboard.enableHistory) {
// in the event history is enabled, and it should be updated it is updated
if (shouldUpdateHistory) {
updateHistory(ClipboardItem.fromClipData(it, false))
} else {
shouldUpdateHistory = true
}
}
}
}
fun hasPrimaryClip(): Boolean {
return this.primaryClip != null
}
/**
* Cleans up.
*
* Sets [instance] to null for GC. Unregisters the system clipboard listener, cancels clipboard clean ups.
*/
override fun close() {
systemClipboardManager.removePrimaryClipChangedListener(this)
handler.cancelAll()
instance = null
}
/**
* Initialize the floris clipboard manager. Exists to avoid dependency loop due to reference
* to [FlorisBoard.context]
*
* Sets up the clipboard cleanup task, links the recycler view in clipInputManager to [history].
*
* @param context Required to register as an onPrimaryClipChangedListener of ClipboardManager
*/
fun initialize(context: Context) {
this.systemClipboardManager = (context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager)
systemClipboardManager.addPrimaryClipChangedListener(this)
prefHelper = PrefHelper.getDefaultInstance(context)
val cleanUpClipboard = Runnable {
if (!prefHelper.clipboard.cleanUpOld) {
return@Runnable
}
val currentTime = System.currentTimeMillis()
var numToPop = 0
val expiryTime = prefHelper.clipboard.cleanUpAfter * 60 * 1000
for (item in history.asReversed()) {
if (item.timeUTC + expiryTime < currentTime) {
numToPop += 1
} else {
break
}
}
for (i in 0 until numToPop) {
history.removeLast().data.close()
}
ClipboardInputManager.getInstance().notifyItemRangeRemoved(pins.size + history.size, numToPop)
}
FlorisBoard.getInstance().clipInputManager.initClipboard(this.history, this.pins)
handler = Handler(Looper.getMainLooper())
prefHelper
handler.postAtScheduledRate(0, INTERVAL, cleanUpClipboard)
executor = FlorisBoard.getInstance().asyncExecutor
executor.execute {
pinsDao = PinnedItemsDatabase.getInstance().clipboardItemDao()
pinsDao.getAll().toCollection(this.pins)
FlorisContentProvider.getInstance().initIfNotAlready()
}
}
/**
* Clears the history with an animation.
*/
fun clearHistoryWithAnimation() {
val clipInputManager = FlorisBoard.getInstance().clipInputManager
val delay = clipInputManager.clearClipboardWithAnimation(pins.size, history.size)
handler.postDelayed({
val size = history.size
for (item in history) {
item.data.close()
}
history.clear()
clipInputManager.notifyItemRangeRemoved(pins.size, size)
}, delay)
}
fun pinClip(adapterPos: Int) {
val clipInputManager = FlorisBoard.getInstance().clipInputManager
val pin = history.removeAt(adapterPos - pins.size)
pins.addFirst(pin.data)
clipInputManager.notifyItemMoved(adapterPos, 0)
clipInputManager.notifyItemChanged(0)
executor.execute {
val uid = pinsDao.insert(pin.data)
pin.data.uid = uid
}
}
/**
* Get the item at a particular [adapterPos] (i.e the position the item is displayed at.)
*/
fun peekHistoryOrPin(adapterPos: Int): ClipboardItem {
return when {
adapterPos < pins.size -> pins[adapterPos]
else -> history[adapterPos - pins.size].data
}
}
fun isPinned(position: Int): Boolean {
return when {
position < pins.size -> true
else -> false
}
}
fun unpinClip(adapterPos: Int) {
val clipInputManager = FlorisBoard.getInstance().clipInputManager
val item = pins.removeAt(adapterPos)
val clipboardPrefs = prefHelper.clipboard
if (clipboardPrefs.limitHistorySize) {
var numRemoved = 0
while (history.size >= clipboardPrefs.maxHistorySize) {
numRemoved += 1
history.removeLast().data.close()
}
ClipboardInputManager.getInstance().notifyItemRangeRemoved(history.size, numRemoved)
}
val timed = TimedClipData(item, System.currentTimeMillis())
history.addFirst(timed)
clipInputManager.notifyItemMoved(adapterPos, pins.size)
clipInputManager.notifyItemChanged(pins.size)
executor.execute {
pinsDao.delete(item)
}
}
fun removeClip(pos: Int) {
when {
pos < pins.size -> {
val item = pins.removeAt(pos)
executor.execute {
Timber.d("removing pin")
pinsDao.delete(item)
}
item.close()
}
else -> {
history.removeAt(pos - pins.size).data.close()
}
}
val clipboardInputManager = ClipboardInputManager.getInstance()
clipboardInputManager.notifyItemRemoved(pos)
}
fun pasteItem(pos: Int) {
val item = peekHistoryOrPin(pos)
FlorisBoard.getInstance().activeEditorInstance.commitClipboardItem(item)
}
/**
* Returns true if the editor can accept the clip item, else false.
*/
fun canBePasted(clipItem: ClipboardItem?): Boolean {
if (clipItem == null) return false
return clipItem.mimeTypes.contains("text/plain") || FlorisBoard.getInstance().activeEditorInstance.contentMimeTypes?.any { editorType ->
clipItem.mimeTypes.any { clipType ->
if (editorType != null) {
compareMimeTypes(clipType, editorType)
}else { false }
}
} == true
}
}

View File

@@ -0,0 +1,75 @@
package dev.patrickgold.florisboard.ime.clip.provider
import android.net.Uri
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import timber.log.Timber
import java.io.File
/**
* Backend class which is used by [FlorisContentProvider] to serve content.
*/
class FileStorage private constructor() {
companion object {
private const val BUF_SIZE = 1024 * 8
private var instance: FileStorage? = null
private var offset = 0
fun getInstance() : FileStorage {
if (this.instance == null){
this.instance = FileStorage()
}
return instance!!
}
}
/**
* Clones a content URI to internal storage.
* @param uri The URI
* @return the file's name which is a unique long
*/
@Synchronized
fun cloneURI(uri: Uri) : Long {
val context = FlorisBoard.getInstance().context
// nanoTime + the number of items created so that it's unique.
val name = (System.nanoTime() + offset)
// Just a normal copy from input stream to output stream.
val source = context.contentResolver.openInputStream(uri)!!
val sink = File(context.filesDir, name.toString()).outputStream()
var nread = 0L
val buf = ByteArray(BUF_SIZE)
var n: Int
while (source.read(buf).also { n = it } > 0) {
sink.write(buf, 0, n)
nread += n.toLong()
}
source.close()
sink.close()
return name
}
/**
* Deletes the file corresponding to an id.
*/
fun deleteById(id: Long) {
Timber.d("Cleaning up $id")
val file = File(FlorisBoard.getInstance().filesDir, id.toString())
file.delete()
}
/**
* Get the file address of an id.
*/
fun getAddress(id: Long): String {
return FlorisBoard.getInstance().filesDir.toString() + "/$id"
}
}

View File

@@ -0,0 +1,132 @@
package dev.patrickgold.florisboard.ime.clip.provider
import android.content.*
import android.database.Cursor
import android.net.Uri
import android.os.ParcelFileDescriptor
import androidx.room.Room
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import timber.log.Timber
import java.io.File
import java.util.concurrent.ExecutorService
/**
* Allows apps to access images on the clipboard.
*
* This is sometimes called by the UI thread, so all functions are non blocking.
* Database accesses are performed async.
*/
class FlorisContentProvider : ContentProvider() {
private lateinit var fileUriDao: FileUriDao
private val mimeTypes: HashMap<Long, Array<String>> = hashMapOf()
private lateinit var executor: ExecutorService
override fun onCreate(): Boolean {
instance = this
return true
}
fun initIfNotAlready(){
if (this::fileUriDao.isInitialized){
return
}
fileUriDao = Room.databaseBuilder(
context!!,
FileUriDatabase::class.java, "fileuridb"
).build().fileUriDao()
executor = FlorisBoard.getInstance().asyncExecutor
for (fileUri in fileUriDao.getAll()) {
mimeTypes[fileUri.fileName] = fileUri.mimeTypes
}
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? {
// just return nothing, nothing should call this function at all.
return null
}
override fun getType(uri: Uri): String {
return when (matcher.match(uri)) {
CLIP_ITEM -> mimeTypes.getOrElse(ContentUris.parseId(uri), { throw IllegalArgumentException("Don't have this item!") })[0]
CLIPS_TABLE -> "vnd.android.cursor.dir/$AUTHORITY.clip"
else -> throw IllegalArgumentException("Don't know what this is $uri")
}
}
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor {
val id = ContentUris.parseId(uri)
val path = File(FileStorage.getInstance().getAddress(id))
// Nothing has permission to write anyway.
return ParcelFileDescriptor.open(path, ParcelFileDescriptor.MODE_READ_ONLY)
}
override fun insert(uri: Uri, values: ContentValues?): Uri {
when (matcher.match(uri)){
CLIPS_TABLE -> {
val id = FileStorage.getInstance().cloneURI(Uri.parse(values?.getAsString("uri")))
val mimes = values?.getAsString("mimetypes")?.split(",")?.toTypedArray()
mimes?.let {
mimeTypes[id] = mimes
executor.execute {
Timber.d("Inserted file uri $id")
fileUriDao.insert(FileUri(id, mimes))
}
}
return ContentUris.withAppendedId(CLIPS_URI, id)
}
else -> throw IllegalArgumentException("Don't know what this is $uri")
}
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
when (matcher.match(uri)){
CLIP_ITEM -> {
val id = ContentUris.parseId(uri)
FileStorage.getInstance().deleteById(id)
mimeTypes.remove(id)
context?.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
executor.execute {
fileUriDao.delete(id)
}
return 1
}
else -> throw IllegalArgumentException("Don't know what this is $uri")
}
}
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
throw IllegalArgumentException("This ContentProvider does not support update.")
}
companion object {
private var instance: FlorisContentProvider? = null
const val AUTHORITY = "dev.patrickgold.florisboard.provider.clip"
val CONTENT_URI: Uri = Uri.parse("content://$AUTHORITY")
val CLIPS_URI: Uri = Uri.parse("content://$AUTHORITY/clips")
fun getInstance(): FlorisContentProvider {
return instance!!
}
private const val CLIPS_TABLE = 1
private const val CLIP_ITEM = 0
val matcher: UriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(AUTHORITY, "clips/#", CLIP_ITEM)
addURI(AUTHORITY, "clips", CLIPS_TABLE)
}
}
}

View File

@@ -0,0 +1,258 @@
package dev.patrickgold.florisboard.ime.clip.provider
import android.content.ClipData
import android.content.ContentValues
import android.net.Uri
import android.provider.BaseColumns
import androidx.room.*
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import java.io.Closeable
enum class ItemType(val value: Int) {
TEXT(1),
IMAGE(2);
companion object {
fun fromInt(value : Int) : ItemType {
return values().first { it.value == value }
}
}
}
/**
* Represents an item on the clipboard.
* The URI stored belongs to FlorisContentProvider, not whatever app copied the image
*
* If type == ItemType.IMAGE there must be a uri set
* if type == ItemType.TEXT there must be a text set
*/
@Entity(tableName = "pins")
data class ClipboardItem(
/** Only used for pins */
@PrimaryKey(autoGenerate = true) @ColumnInfo(name=BaseColumns._ID, index=true) var uid: Long?,
val type: ItemType,
val uri: Uri?,
val text: String?,
val mimeTypes: Array<String>) : Closeable{
/**
* Creates a new ClipData which has the same contents as this.
*/
fun toClipData(): ClipData {
return when (type) {
ItemType.IMAGE -> {
ClipData.newUri(FlorisBoard.getInstance().context.contentResolver, "Clipboard data", uri)
}
ItemType.TEXT -> {
ClipData.newPlainText("Clipboard data", text)
}
}
}
/**
* Instructs the content provider to delete this URI. If not an image, is a noop
*/
override fun close() {
if (type == ItemType.IMAGE) {
FlorisBoard.getInstance().context.contentResolver.delete(this.uri!!, null, null)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ClipboardItem
if (uid != other.uid) return false
if (type != other.type) return false
if (uri != other.uri) return false
if (text != other.text) return false
if (!mimeTypes.contentEquals(other.mimeTypes)) return false
return true
}
override fun hashCode(): Int {
var result = uid.hashCode()
result = 31 * result + type.hashCode()
result = 31 * result + (uri?.hashCode() ?: 0)
result = 31 * result + (text?.hashCode() ?: 0)
result = 31 * result + mimeTypes.contentHashCode()
return result
}
fun stringRepresentation(): String {
return when {
uri != null -> "(Image) $uri"
text != null -> text
else -> "#ERROR"
}
}
companion object {
/**
* So that every item doesn't have to allocate its own array.
*/
val TEXT_PLAIN = arrayOf("text/plain")
/**
* Returns a new ClipboardItem based on a ClipData
*
* @param data The ClipData to clone.
* @param cloneUri Whether to store the image using [FlorisContentProvider].
*/
fun fromClipData(data: ClipData, cloneUri: Boolean) : ClipboardItem {
val type = when {
data.getItemAt(0)?.uri != null -> ItemType.IMAGE
data.getItemAt(0)?.text != null -> ItemType.TEXT
else -> null
}!!
val uri = if (type == ItemType.IMAGE) {
if (data.getItemAt(0).uri.authority == FlorisContentProvider.CONTENT_URI.authority || !cloneUri){
data.getItemAt(0).uri
}else {
val values = ContentValues().apply{
put("uri", data.getItemAt(0).uri.toString())
put("mimetypes", data.description.filterMimeTypes("*/*").joinToString(","))
}
FlorisBoard.getInstance().context.contentResolver.insert(FlorisContentProvider.CLIPS_URI, values)
}
} else { null }
val text = data.getItemAt(0).text?.toString()
val mimeTypes = when (type) {
ItemType.IMAGE -> {
(0 until data.description.mimeTypeCount).map {
data.description.getMimeType(it)
}.toTypedArray()
}
ItemType.TEXT -> { TEXT_PLAIN }
}
return ClipboardItem(null, type, uri, text, mimeTypes)
}
}
}
class Converters {
@TypeConverter
fun uriFromString(value: String?): Uri? {
return Uri.parse(value)
}
@TypeConverter
fun stringFromUri(value: Uri?): String {
return value.toString()
}
@TypeConverter
fun itemTypeToInt(value: ItemType?): Int? {
return value?.value
}
@TypeConverter
fun intToItemType(value: Int?): ItemType? {
return value?.let { ItemType.fromInt(it) }
}
/**
* Only works because the string array is a mimetype.
* DOES NOT USE A GENERALIZED FORMAT.
*/
@TypeConverter
fun mimeTypesToString(mimeTypes: Array<String>): String {
return mimeTypes.joinToString(",")
}
@TypeConverter
fun stringToMimeTypes(value: String): Array<String> {
return value.split(",").toTypedArray()
}
}
@Dao
interface PinnedClipboardItemDao {
@Query("SELECT * FROM pins")
fun getAll(): List<ClipboardItem>
@Insert
fun insert(item: ClipboardItem) : Long
@Delete
fun delete(item: ClipboardItem)
}
@Database(entities = [ClipboardItem::class], version = 1)
@TypeConverters(Converters::class)
abstract class PinnedItemsDatabase : RoomDatabase() {
abstract fun clipboardItemDao() : PinnedClipboardItemDao
companion object {
private var instance: PinnedItemsDatabase? = null
fun getInstance(): PinnedItemsDatabase {
if (instance == null) {
instance = Room.databaseBuilder(
FlorisBoard.getInstance().context,
PinnedItemsDatabase::class.java,
"pins").build()
}
return instance!!
}
}
}
@Entity(tableName = "file_uris")
data class FileUri(
@PrimaryKey @ColumnInfo(name=BaseColumns._ID, index=true) val fileName: Long,
val mimeTypes: Array<String>
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as FileUri
if (fileName != other.fileName) return false
if (!mimeTypes.contentEquals(other.mimeTypes)) return false
return true
}
override fun hashCode(): Int {
var result = 31 + fileName.hashCode()
result = 31 * result + mimeTypes.contentHashCode()
return result
}
}
@Dao
interface FileUriDao {
@Query("SELECT * FROM file_uris WHERE ${BaseColumns._ID} == (:uid)")
fun getById(uid: Long) : FileUri
@Query("DELETE FROM file_uris WHERE ${BaseColumns._ID} == (:id)")
fun delete(id: Long)
@Insert
fun insert(vararg fileUris: FileUri)
@Query("SELECT COUNT(*) FROM file_uris WHERE ${BaseColumns._ID} == (:id)")
fun numberWithId(id: Long): Int
@Query("SELECT * FROM file_uris")
fun getAll(): List<FileUri>
}
@Database(entities = [FileUri::class], version = 1)
@TypeConverters(Converters::class)
abstract class FileUriDatabase : RoomDatabase() {
abstract fun fileUriDao() : FileUriDao
}

View File

@@ -16,6 +16,8 @@
package dev.patrickgold.florisboard.ime.core
import android.content.ClipDescription
import android.content.Intent
import android.inputmethodservice.InputMethodService
import android.os.Build
import android.os.SystemClock
@@ -26,6 +28,12 @@ import android.view.KeyEvent
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.annotation.RequiresApi
import androidx.core.view.inputmethod.InputConnectionCompat
import androidx.core.view.inputmethod.InputContentInfoCompat
import dev.patrickgold.florisboard.ime.clip.FlorisClipboardManager
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.clip.provider.ItemType
import timber.log.Timber
/**
* Class which holds information relevant to an editor instance like the [cachedInput], [selection],
@@ -36,10 +44,12 @@ class EditorInstance private constructor(
private val ims: InputMethodService?,
val imeOptions: ImeOptions,
val inputAttributes: InputAttributes,
val packageName: String
val packageName: String,
private val editorInfo: EditorInfo
) {
val cachedInput: CachedInput = CachedInput(this)
var contentMimeTypes: Array<out String?>? = null
private val florisClipboardManager: FlorisClipboardManager = FlorisClipboardManager.getInstance()
val cursorCapsMode: InputAttributes.CapsMode
get() {
val ic = inputConnection ?: return InputAttributes.CapsMode.NONE
@@ -75,7 +85,8 @@ class EditorInstance private constructor(
ims = null,
imeOptions = ImeOptions.fromImeOptionsInt(EditorInfo.IME_NULL),
inputAttributes = InputAttributes.fromInputTypeInt(InputType.TYPE_NULL),
packageName = "undefined"
packageName = "undefined",
editorInfo = EditorInfo()
)
}
@@ -85,7 +96,8 @@ class EditorInstance private constructor(
ims = ims,
imeOptions = ImeOptions.fromImeOptionsInt(editorInfo.imeOptions),
inputAttributes = InputAttributes.fromInputTypeInt(editorInfo.inputType),
packageName = editorInfo.packageName
packageName = editorInfo.packageName,
editorInfo = editorInfo
).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
contentMimeTypes = editorInfo.contentMimeTypes
@@ -198,6 +210,41 @@ class EditorInstance private constructor(
}
}
/**
* Commits the given [ClipboardItem]. If the clip data is text (incl. HTML), it delegates to [commitText].
* If the item has a content URI (and the EditText supports it), the item is committed as rich data.
* This allows for committing (e.g) images.
*
* @param item The ClipboardItem to commit
* @return True on success, false if something went wrong.
*/
fun commitClipboardItem(item: ClipboardItem): Boolean {
val mimeTypes = item.mimeTypes
return when (item.type){
ItemType.IMAGE -> {
val inputContentInfo = InputContentInfoCompat(
item.uri!!,
ClipDescription("clipboard image", mimeTypes),
null
)
val ic = inputConnection ?: return false
ic.finishComposingText()
var flags = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
flags = flags or InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION
}else {
FlorisBoard.getInstance().context.grantUriPermission(editorInfo.packageName, item.uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
InputConnectionCompat.commitContent(ic, editorInfo, inputContentInfo, flags, null)
}
ItemType.TEXT -> {
commitText(item.text.toString())
}
}
}
/**
* Executes a backward delete on this editor's text. If a text selection is active, all
* characters inside this selection will be removed, else only the left-most character from
@@ -230,12 +277,14 @@ class EditorInstance private constructor(
ic.beginBatchEdit()
markComposingRegion(null)
getWordsInString(cachedInput.rawText.substring(0,
(selection.start - cachedInput.offset).coerceAtLeast(0))).run {
get(size - n.coerceAtLeast(0)).range
}.run {
ic.setSelection(first + cachedInput.offset, selection.start)
}
try {
getWordsInString(cachedInput.rawText.substring(0,
(selection.start - cachedInput.offset).coerceAtLeast(0))).run {
get(size - n.coerceAtLeast(0)).range
}.run {
ic.setSelection(first + cachedInput.offset, selection.start)
}
} catch (e: Exception) {}
ic.commitText("", 1)
@@ -355,15 +404,11 @@ class EditorInstance private constructor(
* @return True on success, false if an error occurred or the input connection is invalid.
*/
fun performClipboardCut(): Boolean {
Timber.d("performClipboardCut")
isPhantomSpaceActive = false
wasPhantomSpaceActiveLastUpdate = false
val ic = inputConnection ?: return false
if (isRawInputEditor) {
sendDownUpKeyEvent(KeyEvent.KEYCODE_X, meta(ctrl = true))
} else {
ic.performContextMenuAction(android.R.id.cut)
}
return true
florisClipboardManager.addNewPlaintext(selection.text)
return sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL)
}
/**
@@ -373,17 +418,11 @@ class EditorInstance private constructor(
* @return True on success, false if an error occurred or the input connection is invalid.
*/
fun performClipboardCopy(): Boolean {
Timber.d("performClipboardCopy")
isPhantomSpaceActive = false
wasPhantomSpaceActiveLastUpdate = false
val ic = inputConnection ?: return false
if (isRawInputEditor) {
sendDownUpKeyEvent(KeyEvent.KEYCODE_C, meta(ctrl = true)) &&
sendDownUpKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT)
} else {
ic.performContextMenuAction(android.R.id.copy)
selection.updateAndNotify(selection.end, selection.end)
}
return true
florisClipboardManager.addNewPlaintext(selection.text)
return selection.updateAndNotify(selection.end, selection.end)
}
/**
@@ -395,13 +434,8 @@ class EditorInstance private constructor(
fun performClipboardPaste(): Boolean {
isPhantomSpaceActive = false
wasPhantomSpaceActiveLastUpdate = false
val ic = inputConnection ?: return false
if (isRawInputEditor) {
sendDownUpKeyEvent(KeyEvent.KEYCODE_V, meta(ctrl = true))
} else {
ic.performContextMenuAction(android.R.id.paste)
}
return true
Timber.d("Before commit clip data")
return commitClipboardItem(florisClipboardManager.primaryClip!!)
}
/**

View File

@@ -17,7 +17,6 @@
package dev.patrickgold.florisboard.ime.core
import android.annotation.SuppressLint
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
@@ -42,6 +41,8 @@ import androidx.lifecycle.*
import com.squareup.moshi.Json
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.clip.ClipboardInputManager
import dev.patrickgold.florisboard.ime.clip.FlorisClipboardManager
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
import dev.patrickgold.florisboard.ime.media.MediaInputManager
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
@@ -58,6 +59,9 @@ import dev.patrickgold.florisboard.util.*
import timber.log.Timber
import java.lang.ref.WeakReference
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
/**
* Variable which holds the current [FlorisBoard] instance. To get this instance from another
@@ -69,7 +73,7 @@ private var florisboardInstance: FlorisBoard? = null
* Core class responsible to link together both the text and media input managers as well as
* managing the one-handed UI.
*/
class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPrimaryClipChangedListener,
class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardManager.OnPrimaryClipChangedListener,
ThemeManager.OnThemeUpdatedListener {
lateinit var prefs: PrefHelper
@@ -89,7 +93,7 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
private var audioManager: AudioManager? = null
var imeManager:InputMethodManager? = null
var clipboardManager: ClipboardManager? = null
var florisClipboardManager: FlorisClipboardManager? = null
private val themeManager: ThemeManager = ThemeManager.default()
private var vibrator: Vibrator? = null
private val osHandler = Handler()
@@ -116,14 +120,20 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
val textInputManager: TextInputManager
val mediaInputManager: MediaInputManager
val clipInputManager: ClipboardInputManager
var isClipboardContextMenuShown = false
init {
florisboardInstance = this
textInputManager = TextInputManager.getInstance()
mediaInputManager = MediaInputManager.getInstance()
clipInputManager = ClipboardInputManager.getInstance()
}
lateinit var asyncExecutor: ExecutorService
companion object {
private const val IME_ID: String = "dev.patrickgold.florisboard/.ime.core.FlorisBoard"
private const val IME_ID_BETA: String = "dev.patrickgold.florisboard.beta/dev.patrickgold.florisboard.ime.core.FlorisBoard"
@@ -209,13 +219,10 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
)
}*/
Timber.i("onCreate()")
serviceLifecycleDispatcher.onServicePreSuperOnCreate()
imeManager = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
audioManager = getSystemService(Context.AUDIO_SERVICE) as? AudioManager
clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
clipboardManager?.addPrimaryClipChangedListener(this)
vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator
prefs = PrefHelper.getDefaultInstance(this)
prefs.initDefaultPreferences()
@@ -231,6 +238,11 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
AppVersionUtils.updateVersionOnInstallAndLastUse(this, prefs)
asyncExecutor = Executors.newSingleThreadExecutor()
florisClipboardManager = FlorisClipboardManager.getInstance()
florisClipboardManager!!.initialize(context)
florisClipboardManager?.addPrimaryClipChangedListener(this)
super.onCreate()
eventListeners.toList().forEach { it?.onCreate() }
}
@@ -282,7 +294,8 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
Timber.i("onDestroy()")
themeManager.unregisterOnThemeUpdatedListener(this)
clipboardManager?.removePrimaryClipChangedListener(this)
florisClipboardManager!!.removePrimaryClipChangedListener(this)
florisClipboardManager!!.close()
osHandler.removeCallbacksAndMessages(null)
florisboardInstance = null
@@ -340,7 +353,6 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
override fun onStartInput(attribute: EditorInfo?, restarting: Boolean) {
Timber.i("onStartInput($attribute, $restarting)")
super.onStartInput(attribute, restarting)
currentInputConnection?.requestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR)
}
@@ -568,6 +580,7 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
val inputView = this.inputView ?: return
val inputWindowView = this.inputWindowView ?: return
// TODO: Check also if the keyboard is currently suppressed by a hardware keyboard
if (!isInputViewShown) {
outInsets?.contentTopInsets = inputWindowView.height
outInsets?.visibleTopInsets = inputWindowView.height
@@ -576,6 +589,11 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
val visibleTopY = inputWindowView.height - inputView.measuredHeight
outInsets?.contentTopInsets = visibleTopY
outInsets?.visibleTopInsets = visibleTopY
if (isClipboardContextMenuShown) {
outInsets?.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME
outInsets?.touchableRegion?.setEmpty()
}
}
/**
@@ -725,16 +743,21 @@ class FlorisBoard : InputMethodService(), LifecycleOwner, ClipboardManager.OnPri
private fun onSubtypeChanged(newSubtype: Subtype) {
textInputManager.onSubtypeChanged(newSubtype)
mediaInputManager.onSubtypeChanged(newSubtype)
clipInputManager.onSubtypeChanged(newSubtype)
}
fun setActiveInput(type: Int) {
when (type) {
R.id.text_input -> {
inputView?.mainViewFlipper?.displayedChild = 0
textInputManager.inputEventDispatcher.send(InputKeyEvent.downUp(KeyData.VIEW_CHARACTERS))
}
R.id.media_input -> {
inputView?.mainViewFlipper?.displayedChild = 1
}
R.id.clip_input -> {
inputView?.mainViewFlipper?.displayedChild = 2
}
}
}

View File

@@ -21,7 +21,6 @@ import android.content.res.Configuration
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.ViewFlipper
import dev.patrickgold.florisboard.R
@@ -47,6 +46,10 @@ class InputView : LinearLayout {
private set
var desiredMediaKeyboardViewHeight: Float = resources.getDimension(R.dimen.mediaKeyboardView_baseHeight)
private set
var heightFactor: Float = 1.0f
private set
var shouldGiveAdditionalSpace: Boolean = false
private set
var mainViewFlipper: ViewFlipper? = null
private set
@@ -76,7 +79,7 @@ class InputView : LinearLayout {
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val heightFactor = when (resources.configuration.orientation) {
heightFactor = when (resources.configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> 1.0f
else -> if (prefs.keyboard.oneHandedMode != OneHandedMode.OFF) {
prefs.keyboard.oneHandedModeScaleFactor / 100.0f
@@ -98,12 +101,12 @@ class InputView : LinearLayout {
var baseSmartbarHeight = 0.16129f * baseHeight
var baseTextInputHeight = baseHeight - baseSmartbarHeight
val tim = florisboard.textInputManager
val shouldGiveAdditionalSpace = prefs.keyboard.numberRow &&
shouldGiveAdditionalSpace = prefs.keyboard.numberRow &&
!(tim.getActiveKeyboardMode() == KeyboardMode.NUMERIC ||
tim.getActiveKeyboardMode() == KeyboardMode.PHONE ||
tim.getActiveKeyboardMode() == KeyboardMode.PHONE2)
if (shouldGiveAdditionalSpace) {
val additionalHeight = desiredTextKeyboardViewHeight * 0.18f
val additionalHeight = baseTextInputHeight * 0.25f
baseHeight += additionalHeight
baseTextInputHeight += additionalHeight
}

View File

@@ -28,6 +28,7 @@ import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.gestures.VelocityThreshold
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.key.UtilityKeyAction
import dev.patrickgold.florisboard.ime.text.smartbar.CandidateView
import dev.patrickgold.florisboard.ime.theme.ThemeMode
import dev.patrickgold.florisboard.util.TimeUtil
import dev.patrickgold.florisboard.util.VersionName
@@ -53,6 +54,7 @@ class PrefHelper(
val smartbar = Smartbar(this)
val suggestion = Suggestion(this)
val theme = Theme(this)
val clipboard = Clipboard(this)
/**
* Checks the cache if an entry for [key] exists, else calls [getPrefInternal] to retrieve the
@@ -310,27 +312,28 @@ class PrefHelper(
class Keyboard(private val prefHelper: PrefHelper) {
companion object {
const val BOTTOM_OFFSET_PORTRAIT = "keyboard__bottom_offset_portrait"
const val BOTTOM_OFFSET_LANDSCAPE = "keyboard__bottom_offset_landscape"
const val FONT_SIZE_MULTIPLIER_PORTRAIT = "keyboard__font_size_multiplier_portrait"
const val FONT_SIZE_MULTIPLIER_LANDSCAPE = "keyboard__font_size_multiplier_landscape"
const val HEIGHT_FACTOR = "keyboard__height_factor"
const val HEIGHT_FACTOR_CUSTOM = "keyboard__height_factor_custom"
const val HINTED_NUMBER_ROW_MODE = "keyboard__hinted_number_row_mode"
const val HINTED_SYMBOLS_MODE = "keyboard__hinted_symbols_mode"
const val KEY_SPACING_HORIZONTAL = "keyboard__key_spacing_horizontal"
const val KEY_SPACING_VERTICAL = "keyboard__key_spacing_vertical"
const val LANDSCAPE_INPUT_UI_MODE = "keyboard__landscape_input_ui_mode"
const val LONG_PRESS_DELAY = "keyboard__long_press_delay"
const val NUMBER_ROW = "keyboard__number_row"
const val ONE_HANDED_MODE = "keyboard__one_handed_mode"
const val ONE_HANDED_MODE_SCALE_FACTOR = "keyboard__one_handed_mode_scale_factor"
const val POPUP_ENABLED = "keyboard__popup_enabled"
const val SOUND_ENABLED = "keyboard__sound_enabled"
const val SOUND_VOLUME = "keyboard__sound_volume"
const val UTILITY_KEY_ACTION = "keyboard__utility_key_action"
const val UTILITY_KEY_ENABLED = "keyboard__utility_key_enabled"
const val VIBRATION_ENABLED = "keyboard__vibration_enabled"
const val VIBRATION_STRENGTH = "keyboard__vibration_strength"
const val BOTTOM_OFFSET_LANDSCAPE = "keyboard__bottom_offset_landscape"
const val FONT_SIZE_MULTIPLIER_PORTRAIT = "keyboard__font_size_multiplier_portrait"
const val FONT_SIZE_MULTIPLIER_LANDSCAPE = "keyboard__font_size_multiplier_landscape"
const val HEIGHT_FACTOR = "keyboard__height_factor"
const val HEIGHT_FACTOR_CUSTOM = "keyboard__height_factor_custom"
const val HINTED_NUMBER_ROW_MODE = "keyboard__hinted_number_row_mode"
const val HINTED_SYMBOLS_MODE = "keyboard__hinted_symbols_mode"
const val KEY_SPACING_HORIZONTAL = "keyboard__key_spacing_horizontal"
const val KEY_SPACING_VERTICAL = "keyboard__key_spacing_vertical"
const val LANDSCAPE_INPUT_UI_MODE = "keyboard__landscape_input_ui_mode"
const val LONG_PRESS_DELAY = "keyboard__long_press_delay"
const val NUMBER_ROW = "keyboard__number_row"
const val ONE_HANDED_MODE = "keyboard__one_handed_mode"
const val ONE_HANDED_MODE_SCALE_FACTOR = "keyboard__one_handed_mode_scale_factor"
const val POPUP_ENABLED = "keyboard__popup_enabled"
const val SOUND_ENABLED = "keyboard__sound_enabled"
const val SOUND_VOLUME = "keyboard__sound_volume"
const val SPACE_BAR_SWITCHES_TO_CHARACTERS = "keyboard__space_bar_switches_to_characters"
const val UTILITY_KEY_ACTION = "keyboard__utility_key_action"
const val UTILITY_KEY_ENABLED = "keyboard__utility_key_enabled"
const val VIBRATION_ENABLED = "keyboard__vibration_enabled"
const val VIBRATION_STRENGTH = "keyboard__vibration_strength"
}
var bottomOffsetPortrait: Int = 0
@@ -388,6 +391,9 @@ class PrefHelper(
var soundVolume: Int = 0
get() = prefHelper.getPref(SOUND_VOLUME, -1)
private set
var spaceBarSwitchesToCharacters: Boolean
get() = prefHelper.getPref(SPACE_BAR_SWITCHES_TO_CHARACTERS, true)
set(v) = prefHelper.setPref(SPACE_BAR_SWITCHES_TO_CHARACTERS, v)
var utilityKeyAction: UtilityKeyAction
get() = UtilityKeyAction.fromString(prefHelper.getPref(UTILITY_KEY_ACTION, UtilityKeyAction.DYNAMIC_SWITCH_LANGUAGE_EMOJIS.toString()))
set(v) = prefHelper.setPref(UTILITY_KEY_ACTION, v)
@@ -439,20 +445,28 @@ class PrefHelper(
class Suggestion(private val prefHelper: PrefHelper) {
companion object {
const val BLOCK_POSSIBLY_OFFENSIVE = "suggestion__block_possibly_offensive"
const val CLIPBOARD_CONTENT_ENABLED = "suggestion__clipboard_content_enabled"
const val CLIPBOARD_CONTENT_TIMEOUT = "suggestion__clipboard_content_timeout"
const val DISPLAY_MODE = "suggestion__display_mode"
const val ENABLED = "suggestion__enabled"
const val SUGGEST_CLIPBOARD_CONTENT = "suggestion__suggest_clipboard_content"
const val USE_PREV_WORDS = "suggestion__use_prev_words"
}
var blockPossiblyOffensive: Boolean
get() = prefHelper.getPref(BLOCK_POSSIBLY_OFFENSIVE, true)
set(v) = prefHelper.setPref(BLOCK_POSSIBLY_OFFENSIVE, v)
var clipboardContentEnabled: Boolean
get() = prefHelper.getPref(CLIPBOARD_CONTENT_ENABLED, false)
set(v) = prefHelper.setPref(CLIPBOARD_CONTENT_ENABLED, v)
var clipboardContentTimeout: Int
get() = prefHelper.getPref(CLIPBOARD_CONTENT_TIMEOUT, 30)
set(v) = prefHelper.setPref(CLIPBOARD_CONTENT_TIMEOUT, v)
var displayMode: CandidateView.DisplayMode
get() = CandidateView.DisplayMode.fromString(prefHelper.getPref(DISPLAY_MODE, CandidateView.DisplayMode.DYNAMIC_SCROLLABLE.toString()))
set(v) = prefHelper.setPref(DISPLAY_MODE, v)
var enabled: Boolean
get() = prefHelper.getPref(ENABLED, true)
set(v) = prefHelper.setPref(ENABLED, v)
var suggestClipboardContent: Boolean
get() = prefHelper.getPref(SUGGEST_CLIPBOARD_CONTENT, false)
set(v) = prefHelper.setPref(SUGGEST_CLIPBOARD_CONTENT, v)
var usePrevWords: Boolean
get() = prefHelper.getPref(USE_PREV_WORDS, true)
set(v) = prefHelper.setPref(USE_PREV_WORDS, v)
@@ -494,4 +508,52 @@ class PrefHelper(
get() = prefHelper.getPref(SUNSET_TIME, TimeUtil.encode(18, 0))
set(v) = prefHelper.setPref(SUNSET_TIME, v)
}
/**
* Wrapper class for clipboard preferences
*/
class Clipboard(private val prefHelper: PrefHelper) {
companion object {
const val ENABLE_INTERNAL = "clipboard__enable_internal"
const val SYNC_TO_SYSTEM = "clipboard__sync_to_system"
const val SYNC_TO_FLORIS = "clipboard__sync_to_floris"
const val ENABLE_HISTORY = "clipboard__enable_history"
const val CLEAN_UP_OLD = "clipboard__clean_up_old"
const val LIMIT_HISTORY_SIZE = "clipboard__limit_history_size"
const val CLEAN_UP_AFTER = "clipboard__clean_up_after"
const val MAX_HISTORY_SIZE = "clipboard__max_history_size"
}
var enableInternal: Boolean
get() = prefHelper.getPref(ENABLE_INTERNAL, false)
set(v) = prefHelper.setPref(ENABLE_INTERNAL, v)
var syncToSystem: Boolean
get() = prefHelper.getPref(SYNC_TO_SYSTEM, false)
set(v) = prefHelper.setPref(SYNC_TO_SYSTEM, v)
var syncToFloris: Boolean
get() = prefHelper.getPref(SYNC_TO_FLORIS, true)
set(v) = prefHelper.setPref(SYNC_TO_FLORIS, v)
var enableHistory: Boolean
get() = prefHelper.getPref(ENABLE_HISTORY, false)
set(v) = prefHelper.setPref(ENABLE_HISTORY, v)
var cleanUpOld: Boolean
get() = prefHelper.getPref(CLEAN_UP_OLD, false)
set(v) = prefHelper.setPref(CLEAN_UP_OLD, v)
var limitHistorySize: Boolean
get() = prefHelper.getPref(LIMIT_HISTORY_SIZE, true)
set(v) = prefHelper.setPref(LIMIT_HISTORY_SIZE, v)
var cleanUpAfter: Int
get() = prefHelper.getPref(CLEAN_UP_AFTER, 20)
set(v) = prefHelper.setPref(CLEAN_UP_AFTER, v)
var maxHistorySize: Int
get() = prefHelper.getPref(MAX_HISTORY_SIZE, 20)
set(v) = prefHelper.setPref(MAX_HISTORY_SIZE, v)
}
}

View File

@@ -176,13 +176,13 @@ class AssetManager private constructor(private val applicationContext: Context)
}
}
fun <T : Asset> loadAsset(uri: Uri, assetClass: KClass<T>): Result<T> {
val rawJsonData = ExternalContentUtils.readTextFromUri(applicationContext, uri).onFailure {
fun <T : Asset> loadAsset(uri: Uri, assetClass: KClass<T>, maxSize: Int): Result<T> {
val rawJsonData = ExternalContentUtils.readTextFromUri(applicationContext, uri, maxSize).getOrElse {
return Result.failure(it)
}
return try {
val adapter = moshi.adapter(assetClass.java)
val asset = adapter.fromJson(rawJsonData.getOrNull()!!)
val asset = adapter.fromJson(rawJsonData)
if (asset != null) {
Result.success(asset)
} else {
@@ -193,7 +193,6 @@ class AssetManager private constructor(private val applicationContext: Context)
}
}
fun loadAssetRaw(ref: AssetRef): Result<String> {
return when (ref.source) {
is AssetSource.Assets -> {

View File

@@ -21,11 +21,16 @@ import android.net.Uri
class ExternalContentUtils private constructor() {
companion object {
fun readTextFromUri(context: Context, uri: Uri): Result<String> {
fun readTextFromUri(context: Context, uri: Uri, maxSize: Int): Result<String> {
val contentResolver = context.contentResolver
?: return Result.failure(NullPointerException("System content resolver not available"))
val inputStream = contentResolver.openInputStream(uri)
?: return Result.failure(NullPointerException("Cannot open input stream for given uri '$uri'"))
val assetFileDescriptor = contentResolver.openAssetFileDescriptor(uri, "r")
?: return Result.failure(NullPointerException("Cannot open asset file descriptor for given uri '$uri'"))
if (assetFileDescriptor.length > maxSize) {
return Result.failure(Exception("Contents of given uri '$uri' exceeds maximum size of $maxSize bytes!"))
}
val rawText = inputStream.bufferedReader(Charsets.UTF_8).use { it.readText() }
return Result.success(rawText)
}
@@ -36,7 +41,7 @@ class ExternalContentUtils private constructor() {
// Must use "rwt" mode to ensure destination file length is truncated after writing.
val outputStream = contentResolver.openOutputStream(uri, "rwt")
?: return Result.failure(NullPointerException("Cannot open output stream for given uri '$uri'"))
outputStream.bufferedWriter(Charsets.UTF_8).use { it.flush(); it.write(text) }
outputStream.bufferedWriter(Charsets.UTF_8).use { it.write(text) }
return Result.success(Unit)
}
}

View File

@@ -18,10 +18,15 @@ package dev.patrickgold.florisboard.ime.popup
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import dev.patrickgold.florisboard.ime.clip.ClipboardPopupManager
import dev.patrickgold.florisboard.ime.clip.ClipboardPopupView
import timber.log.Timber
/**
* Basic helper view class which acts as a non-interactive layer view, which sits above the whole
@@ -41,12 +46,29 @@ class PopupLayerView : FrameLayout {
)
}
var clipboardPopupManager: ClipboardPopupManager? = null
var intercept: ClipboardPopupView? = null
var shouldIntercept = true
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
if (ev != null) {
intercept?.run {
val viewRect = Rect()
getGlobalVisibleRect(viewRect)
return when {
!viewRect.contains(ev.x.toInt(), ev.y.toInt()) -> {
clipboardPopupManager?.hide()
true
}
else -> false
}
}
}
return true
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
override fun onTouchEvent(ev: MotionEvent?): Boolean {
return false
}
}

View File

@@ -48,7 +48,8 @@ class PopupManager<T_KBD: View, T_KV: View>(
KeyCode.ENTER,
KeyCode.LANGUAGE_SWITCH,
KeyCode.SWITCH_TO_TEXT_CONTEXT,
KeyCode.SWITCH_TO_MEDIA_CONTEXT
KeyCode.SWITCH_TO_MEDIA_CONTEXT,
KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT
)
private var keyPopupWidth: Int
private var keyPopupHeight: Int
@@ -108,6 +109,11 @@ class PopupManager<T_KBD: View, T_KV: View>(
PopupExtendedView.Element.Icon(it, adjustedIndex)
} ?: PopupExtendedView.Element.Undefined
}
KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT -> {
getDrawable(keyView.context, R.drawable.ic_assignment)?.let {
PopupExtendedView.Element.Icon(it, adjustedIndex)
} ?: PopupExtendedView.Element.Undefined
}
KeyCode.URI_COMPONENT_TLD -> {
PopupExtendedView.Element.Tld(
keyView.data.popup[adjustedIndex].label, adjustedIndex
@@ -146,10 +152,10 @@ class PopupManager<T_KBD: View, T_KV: View>(
when (keyboardView.resources.configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
if (keyboardView.isSmartbarKeyboardView) {
keyPopupWidth = (keyView.measuredWidth * 0.6f).toInt()
keyPopupWidth = (keyView.measuredWidth * 1.0f).toInt()
keyPopupHeight = (keyboardView.desiredKeyHeight * 3.0f * 1.2f).toInt()
} else {
keyPopupWidth = (keyboardView.desiredKeyWidth * 0.6f).toInt()
keyPopupWidth = (keyboardView.desiredKeyWidth * 1.0f).toInt()
keyPopupHeight = (keyboardView.desiredKeyHeight * 3.0f).toInt()
}
}

View File

@@ -24,6 +24,7 @@ import android.widget.Toast
import android.widget.ViewFlipper
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.core.*
import dev.patrickgold.florisboard.ime.dictionary.Dictionary
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
@@ -272,6 +273,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
updateCapsState()
setActiveKeyboardMode(keyboardMode)
smartbarView?.setCandidateSuggestionWords(System.nanoTime(), null)
smartbarView?.updateSmartbarState()
}
@@ -351,7 +353,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
val suggestions = it.getTokenPredictions(
precedingTokens = listOf(),
currentToken = Token(activeEditorInstance.cachedInput.currentWord.text),
maxSuggestionCount = 3,
maxSuggestionCount = 16,
allowPossiblyOffensive = !florisboard.prefs.suggestion.blockPossiblyOffensive
).toStringList()
if (BuildConfig.DEBUG) {
@@ -365,7 +367,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
}
} else {
smartbarView?.setCandidateSuggestionWords(System.nanoTime(), listOf())
smartbarView?.setCandidateSuggestionWords(System.nanoTime(), null)
}
}
}
@@ -403,6 +405,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
SwipeAction.MOVE_CURSOR_START_OF_PAGE -> KeyData.MOVE_START_OF_PAGE
SwipeAction.MOVE_CURSOR_END_OF_PAGE -> KeyData.MOVE_END_OF_PAGE
SwipeAction.SHIFT -> KeyData.SHIFT
SwipeAction.SWITCH_TO_CLIPBOARD_CONTEXT -> KeyData.SWITCH_TO_CLIPBOARD_CONTEXT
SwipeAction.SHOW_INPUT_METHOD_PICKER -> KeyData.SHOW_INPUT_METHOD_PICKER
else -> null
}
@@ -419,6 +422,10 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
activeEditorInstance.commitCompletion(word)
}
override fun onSmartbarClipboardCandidatePressed(clipboardItem: ClipboardItem) {
activeEditorInstance.commitClipboardItem(clipboardItem)
}
override fun onSmartbarPrivateModeButtonClicked() {
Toast.makeText(florisboard.context, R.string.private_mode_dialog__title, Toast.LENGTH_LONG).show()
}
@@ -556,6 +563,9 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
* enabled by the user.
*/
private fun handleSpace(ev: InputKeyEvent) {
if (florisboard.prefs.keyboard.spaceBarSwitchesToCharacters && getActiveKeyboardMode() != KeyboardMode.CHARACTERS) {
setActiveKeyboardMode(KeyboardMode.CHARACTERS)
}
if (florisboard.prefs.correction.doubleSpacePeriod) {
if (ev.isConsecutiveEventOf(inputEventDispatcher.lastKeyEventUp, florisboard.prefs.keyboard.longPressDelay.toLong())) {
val text = activeEditorInstance.getTextBeforeCursor(2)
@@ -688,28 +698,12 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
KeyCode.CLIPBOARD_CUT -> activeEditorInstance.performClipboardCut()
KeyCode.CLIPBOARD_COPY -> activeEditorInstance.performClipboardCopy()
KeyCode.CLIPBOARD_PASTE -> {
activeEditorInstance.performClipboardPaste()
smartbarView?.resetClipboardSuggestion()
}
KeyCode.CLIPBOARD_PASTE -> activeEditorInstance.performClipboardPaste()
KeyCode.CLIPBOARD_SELECT -> handleClipboardSelect()
KeyCode.CLIPBOARD_SELECT_ALL -> activeEditorInstance.performClipboardSelectAll()
KeyCode.DELETE -> {
handleDelete()
if (ev.action == InputKeyEvent.Action.DOWN_UP || ev.action == InputKeyEvent.Action.UP) {
smartbarView?.resetClipboardSuggestion()
}
}
KeyCode.DELETE_WORD -> {
handleDeleteWord()
if (ev.action == InputKeyEvent.Action.DOWN_UP || ev.action == InputKeyEvent.Action.UP) {
smartbarView?.resetClipboardSuggestion()
}
}
KeyCode.ENTER -> {
handleEnter()
smartbarView?.resetClipboardSuggestion()
}
KeyCode.DELETE -> handleDelete()
KeyCode.DELETE_WORD -> handleDeleteWord()
KeyCode.ENTER -> handleEnter()
KeyCode.INTERNAL_BATCH_EDIT -> {
florisboard.endInternalBatchEdit()
return
@@ -719,8 +713,11 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
KeyCode.SHIFT -> handleShiftUp()
KeyCode.SHIFT_LOCK -> handleShiftLock()
KeyCode.SHOW_INPUT_METHOD_PICKER -> florisboard.imeManager?.showInputMethodPicker()
KeyCode.SPACE -> handleSpace(ev)
KeyCode.SWITCH_TO_MEDIA_CONTEXT -> florisboard.setActiveInput(R.id.media_input)
KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT -> florisboard.setActiveInput(R.id.clip_input)
KeyCode.SWITCH_TO_TEXT_CONTEXT -> florisboard.setActiveInput(R.id.text_input)
KeyCode.CLEAR_CLIPBOARD_HISTORY -> florisboard.florisClipboardManager?.clearHistoryWithAnimation()
KeyCode.TOGGLE_ONE_HANDED_MODE_LEFT -> florisboard.toggleOneHandedMode(isRight = false)
KeyCode.TOGGLE_ONE_HANDED_MODE_RIGHT -> florisboard.toggleOneHandedMode(isRight = true)
KeyCode.VIEW_CHARACTERS -> setActiveKeyboardMode(KeyboardMode.CHARACTERS)
@@ -751,7 +748,6 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
else -> when (data.type) {
KeyType.CHARACTER, KeyType.NUMERIC -> when (data.code) {
KeyCode.SPACE -> handleSpace(ev)
KeyCode.URI_COMPONENT_TLD -> {
val tld = data.label.toLowerCase(Locale.ENGLISH)
activeEditorInstance.commitText(tld)
@@ -771,7 +767,6 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
}
}
smartbarView?.resetClipboardSuggestion()
}
}
if (data.code != KeyCode.SHIFT && !capsLock && !inputEventDispatcher.isPressed(KeyCode.SHIFT)) {

View File

@@ -80,7 +80,11 @@ class EditingKeyboardView : ConstraintLayout, FlorisBoard.EventListener,
else -> View.GONE
}
copyKey?.isEnabled = isSelectionActive
pasteKey?.isEnabled = florisboard?.clipboardManager?.hasPrimaryClip() ?: false
pasteKey?.isEnabled =
florisboard?.florisClipboardManager?.hasPrimaryClip() == true &&
florisboard.activeEditorInstance.contentMimeTypes?.any {
florisboard.florisClipboardManager!!.primaryClip?.mimeTypes?.contains(it) ?: false
} == true
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {

View File

@@ -40,6 +40,7 @@ enum class SwipeAction {
SHOW_INPUT_METHOD_PICKER,
SWITCH_TO_PREV_SUBTYPE,
SWITCH_TO_NEXT_SUBTYPE,
SWITCH_TO_CLIPBOARD_CONTEXT,
SWITCH_TO_PREV_KEYBOARD;
companion object {

View File

@@ -65,9 +65,10 @@ object KeyCode {
const val CLIPBOARD_PASTE_POPUP = -133
const val CLIPBOARD_SELECT = -134
const val CLIPBOARD_SELECT_ALL = -135
const val CLEAR_CLIPBOARD_HISTORY = -136
const val UNDO = -136
const val REDO = -137
const val UNDO = -137
const val REDO = -138
const val PHONE_PAUSE = 44
const val PHONE_WAIT = 59

View File

@@ -161,6 +161,12 @@ open class KeyData(
code = KeyCode.SWITCH_TO_TEXT_CONTEXT,
label = "switch_to_text_context"
)
/** Predefined key data for [KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT] */
val SWITCH_TO_CLIPBOARD_CONTEXT = KeyData(
type = KeyType.SYSTEM_GUI,
code = KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT,
label = "switch_to_clipboard_context"
)
/** Predefined key data for [KeyCode.SHIFT] */
val SHIFT = KeyData(
@@ -189,6 +195,13 @@ open class KeyData(
code = KeyCode.UNSPECIFIED,
label = "unspecified"
)
/** Predefined key data for [KeyCode.VIEW_CHARACTERS] */
val VIEW_CHARACTERS = KeyData(
type = KeyType.SYSTEM_GUI,
code = KeyCode.VIEW_CHARACTERS,
label = "view_characters"
)
}
override fun toString(): String {

View File

@@ -194,7 +194,8 @@ class KeyView(
*/
fun getComputedLetter(
keyData: KeyData = data,
caps: Boolean = florisboard?.textInputManager?.caps ?: false,
caps: Boolean = florisboard?.textInputManager?.caps ?: false &&
florisboard?.textInputManager?.getActiveKeyboardMode() == KeyboardMode.CHARACTERS,
subtype: Subtype = florisboard?.activeSubtype ?: Subtype.DEFAULT
): String {
return if (caps && keyData is FlorisKeyData && keyData.shift != null) {
@@ -292,6 +293,8 @@ class KeyView(
KeyCode.SHIFT -> {
longKeyPressHandler.postDelayed((delayMillis * 2.5).toLong()) {
this.florisboard.textInputManager.inputEventDispatcher.send(InputKeyEvent.downUp(KeyData.SHIFT_LOCK))
florisboard.keyPressVibrate()
florisboard.keyPressSound(data)
}
}
KeyCode.LANGUAGE_SWITCH -> {
@@ -474,7 +477,6 @@ class KeyView(
* by Devunwired
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val keyMarginH: Int
val keyMarginV: Int
@@ -557,7 +559,7 @@ class KeyView(
}
drawablePaddingH = (0.2f * width).toInt()
drawablePaddingV = (0.2f * height).toInt()
drawablePaddingV = (0.2f * height * (1.0f / (florisboard?.inputView?.heightFactor ?: 1.0f)).coerceAtMost(1.0f)).toInt()
// MUST CALL THIS
setMeasuredDimension(width, height)
@@ -580,14 +582,27 @@ class KeyView(
isEnabled = when (data.code) {
KeyCode.CLIPBOARD_COPY,
KeyCode.CLIPBOARD_CUT -> (florisboard != null
&& florisboard.activeEditorInstance.selection.isSelectionMode
&& !florisboard.activeEditorInstance.isRawInputEditor)
KeyCode.CLIPBOARD_PASTE -> florisboard?.clipboardManager?.hasPrimaryClip() == true
&& florisboard.activeEditorInstance.selection.isSelectionMode
&& !florisboard.activeEditorInstance.isRawInputEditor)
KeyCode.CLIPBOARD_PASTE -> (
// such gore. checks
// 1. has a clipboard item
// 2. the clipboard item has any of the supported mime types of the editor OR is plain text.
florisboard?.florisClipboardManager?.canBePasted(florisboard.florisClipboardManager?.primaryClip)
) == true
KeyCode.CLIPBOARD_SELECT_ALL -> {
florisboard?.activeEditorInstance?.isRawInputEditor == false
}
KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT -> {
visibility = when (prefs.clipboard.enableHistory ) {
true -> VISIBLE
false -> GONE
}
prefs.clipboard.enableHistory
}
else -> true
}
if (data.code == KeyCode.CLIPBOARD_PASTE)
if (!isEnabled) {
isKeyPressed = false
}
@@ -720,6 +735,12 @@ class KeyView(
}
}
}
KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT -> {
when (prefs.clipboard.enableHistory) {
true -> VISIBLE
false -> GONE
}
}
KeyCode.LANGUAGE_SWITCH -> {
val tempUtilityKeyAction = when {
prefs.keyboard.utilityKeyEnabled -> prefs.keyboard.utilityKeyAction
@@ -867,6 +888,9 @@ class KeyView(
KeyCode.SWITCH_TO_MEDIA_CONTEXT -> {
drawable = getDrawable(context, R.drawable.ic_sentiment_satisfied)
}
KeyCode.SWITCH_TO_CLIPBOARD_CONTEXT -> {
drawable = getDrawable(context, R.drawable.ic_assignment)
}
KeyCode.SWITCH_TO_TEXT_CONTEXT,
KeyCode.VIEW_CHARACTERS -> {
label = resources.getString(R.string.key__view_characters)

View File

@@ -22,9 +22,10 @@ import android.util.AttributeSet
import android.view.MotionEvent
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.core.view.children
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexboxLayout
import com.google.android.flexbox.JustifyContent
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
@@ -48,7 +49,7 @@ import kotlin.math.roundToInt
*
* @property florisboard Reference to instance of core class [FlorisBoard].
*/
class KeyboardView : LinearLayout, FlorisBoard.EventListener, SwipeGesture.Listener,
class KeyboardView : FlexboxLayout, FlorisBoard.EventListener, SwipeGesture.Listener,
ThemeManager.OnThemeUpdatedListener {
private var activeKeyViews: MutableMap<Int, KeyView> = mutableMapOf()
private var initialKeyCodes: MutableMap<Int, Int> = mutableMapOf()
@@ -77,7 +78,8 @@ class KeyboardView : LinearLayout, FlorisBoard.EventListener, SwipeGesture.Liste
isLoadingPlaceholderKeyboard = getBoolean(R.styleable.KeyboardView_isLoadingPlaceholderKeyboard, false)
recycle()
}
orientation = VERTICAL
flexDirection = FlexDirection.COLUMN
justifyContent = JustifyContent.SPACE_BETWEEN
layoutParams = layoutParams ?: FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
@@ -360,9 +362,17 @@ class KeyboardView : LinearLayout, FlorisBoard.EventListener, SwipeGesture.Liste
} else {
(florisboard?.inputView?.desiredTextKeyboardViewHeight ?: MeasureSpec.getSize(heightMeasureSpec).toFloat())
} * if (isPreviewMode) { 0.90f } else { 1.00f }
val layoutSize = computedLayout?.arrangement?.size?.toFloat() ?: 4.0f
desiredKeyHeight = when {
isSmartbarKeyboardView -> desiredHeight - 1.5f * keyMarginV
else -> desiredHeight / (computedLayout?.arrangement?.size?.toFloat() ?: 4.0f) - 2.0f * keyMarginV
isSmartbarKeyboardView -> {
desiredHeight - 1.5f * keyMarginV
}
florisboard?.inputView?.shouldGiveAdditionalSpace == true -> {
desiredHeight / (layoutSize + 0.5f).coerceAtMost(5.0f) - 2.0f * keyMarginV
}
else -> {
desiredHeight / layoutSize - 2.0f * keyMarginV
}
}.roundToInt()
super.onMeasure(

View File

@@ -209,7 +209,15 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
popupSet = extendedPopups.mapping[KeyVariation.ALL]?.get(label) ?:
extendedPopupsDefault.mapping[KeyVariation.ALL]?.get(label)
}
popupSet?.let { key.popup.merge(it) }
var keySpecificPopupSet: PopupSet<KeyData>? = null
if (label != key.label) {
keySpecificPopupSet = extendedPopups.mapping[KeyVariation.ALL]?.get(key.label) ?:
extendedPopupsDefault.mapping[KeyVariation.ALL]?.get(key.label)
}
key.popup.apply {
keySpecificPopupSet?.let { merge(it) }
popupSet?.let { merge(it) }
}
}
}
}

View File

@@ -0,0 +1,533 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.text.smartbar
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.text.TextPaint
import android.text.TextUtils
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.OverScroller
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.clip.FlorisClipboardManager
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.ime.theme.ThemeValue
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
/**
* A candidate view allowing for easy of suggestions. Additionally it also features an integrated clipboard suggestion
* support, which works together with the normal suggestions provided by the NLP algorithm.
*/
class CandidateView : View, ThemeManager.OnThemeUpdatedListener {
private var themeManager: ThemeManager? = null
private var florisClipboardManager: FlorisClipboardManager? = null
private var eventListener: WeakReference<SmartbarView.EventListener?> = WeakReference(null)
private var displayMode: DisplayMode = DisplayMode.DYNAMIC_SCROLLABLE
private val candidates: ArrayList<String> = ArrayList()
private var clipboardItem: ClipboardItem? = null
private var clipboardItemTime: Long = 0
private var clipboardItemTimeout: Int = 60_000
private var computedCandidates: ArrayList<ComputedCandidate> = ArrayList()
private var computedCandidatesWidthPx: Int = 0
private var selectedIndex: Int = -1
private var backgroundPaint: Paint = Paint().apply { color = Color.BLACK }
private var candidateBackground: ThemeValue = ThemeValue.SolidColor.TRANSPARENT
private var candidateForeground: ThemeValue = ThemeValue.SolidColor.TRANSPARENT
private val candidateMarginH: Int = resources.getDimensionPixelOffset(R.dimen.smartbar_candidate_marginH)
private var dividerBackground: ThemeValue = ThemeValue.SolidColor.TRANSPARENT
private var dividerPaint: Paint = Paint().apply { color = Color.BLACK }
private var dividerWidth: Int = resources.getDimensionPixelSize(R.dimen.smartbar_divider_width)
private val pasteDrawable = ContextCompat.getDrawable(context, R.drawable.ic_content_paste)
private var lastX: Float = 0.0f
private val scroller: OverScroller = OverScroller(context, AccelerateDecelerateInterpolator())
private val textPaint: TextPaint = TextPaint().apply {
alpha = 255
color = Color.BLACK
isAntiAlias = true
isFakeBoldText = false
textAlign = Paint.Align.CENTER
textSize = resources.getDimension(R.dimen.smartbar_candidate_textSize)
typeface = Typeface.DEFAULT
}
private var velocityTracker: VelocityTracker? = null
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init {
isHorizontalScrollBarEnabled = false
isVerticalScrollBarEnabled = false
scrollTo(0, 0)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
themeManager = ThemeManager.defaultOrNull()
themeManager?.registerOnThemeUpdatedListener(this)
florisClipboardManager = FlorisClipboardManager.getInstanceOrNull()
updateCandidates(candidates)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
themeManager?.unregisterOnThemeUpdatedListener(this)
themeManager = null
florisClipboardManager = null
candidates.clear()
velocityTracker?.recycle()
velocityTracker = null
}
fun updateCandidates(newCandidates: List<String>?) {
candidates.clear()
if (newCandidates != null) {
candidates.addAll(newCandidates)
}
recomputeCandidates()
}
fun updateClipboardItem(newClipboardCandidate: ClipboardItem) {
clipboardItem = newClipboardCandidate
clipboardItemTime = System.currentTimeMillis()
recomputeCandidates()
}
fun setEventListener(listener: SmartbarView.EventListener) {
eventListener = WeakReference(listener)
}
fun updateDisplaySettings(newDisplayMode: DisplayMode, newClipboardContentTimeout: Int) {
if (newClipboardContentTimeout != clipboardItemTimeout) {
clipboardItemTimeout = newClipboardContentTimeout
}
if (newDisplayMode != displayMode) {
displayMode = newDisplayMode
scroller.abortAnimation()
scrollTo(0, 0)
}
}
private fun recomputeCandidates() {
computedCandidates.clear()
if (clipboardItem != null && System.currentTimeMillis() - clipboardItemTime > clipboardItemTimeout) {
clipboardItem = null
}
val classicCandidateWidth = (measuredWidth - 2 * dividerWidth) / 3
val maxDynamicCandidateWidth = (measuredWidth * 0.7).toInt()
val clipItem = clipboardItem
val clipItemAvailable = clipItem != null && florisClipboardManager?.canBePasted(clipItem) == true
computedCandidatesWidthPx = 0
if (candidates.isEmpty()) {
if (clipItemAvailable) {
computedCandidates.add(ComputedCandidate.Clip(clipItem!!, Rect(
0,
0,
measuredWidth,
measuredHeight
)))
} else if (displayMode == DisplayMode.CLASSIC) {
for (n in 0 until 3) {
val left = (classicCandidateWidth + dividerWidth) * n
computedCandidates.add(ComputedCandidate.Empty(Rect(
left,
0,
left + classicCandidateWidth,
measuredHeight
)))
}
}
} else if (candidates.size == 1 && !clipItemAvailable) {
computedCandidates.add(ComputedCandidate.Word(candidates[0], Rect(
0,
0,
measuredWidth,
measuredHeight
)))
} else {
when (displayMode) {
DisplayMode.CLASSIC -> {
if (!clipItemAvailable) {
for (n in 0 until candidates.size.coerceAtMost(3)) {
val left = (classicCandidateWidth + dividerWidth) * n
computedCandidates.add(ComputedCandidate.Word(candidates[n], Rect(
left,
0,
left + classicCandidateWidth,
measuredHeight
)))
}
} else {
computedCandidates.add(ComputedCandidate.Clip(clipItem!!, Rect(
0,
0,
classicCandidateWidth,
measuredHeight
)))
for (n in 0 until candidates.size.coerceAtMost(2)) {
val left = (classicCandidateWidth + dividerWidth) * (n + 1)
computedCandidates.add(ComputedCandidate.Word(candidates[n], Rect(
left,
0,
left + classicCandidateWidth,
measuredHeight
)))
}
}
if (computedCandidates.size < 3) {
for (n in computedCandidates.size until 3) {
val left = (classicCandidateWidth + dividerWidth) * n
computedCandidates.add(ComputedCandidate.Empty(Rect(
left,
0,
left + classicCandidateWidth,
measuredHeight
)))
}
}
}
DisplayMode.DYNAMIC -> {
if (clipItemAvailable) {
val candidateWidth = (textPaint.measureText(clipItem!!.stringRepresentation()).toInt() + candidateMarginH + measuredHeight * 4 / 6).coerceAtMost(maxDynamicCandidateWidth)
computedCandidates.add(ComputedCandidate.Clip(clipItem, Rect(
0,
0,
candidateWidth,
measuredHeight
)))
computedCandidatesWidthPx += candidateWidth
}
for (n in candidates.indices) {
var tmpWidthPx = computedCandidatesWidthPx
if (tmpWidthPx > 0) {
tmpWidthPx += dividerWidth
}
val candidateWidth = (textPaint.measureText(candidates[n]).toInt() + 2 * candidateMarginH).coerceAtMost(maxDynamicCandidateWidth)
tmpWidthPx += candidateWidth
if (tmpWidthPx > measuredWidth) {
break
} else {
computedCandidates.add(ComputedCandidate.Word(candidates[n], Rect(
computedCandidatesWidthPx,
0,
computedCandidatesWidthPx + candidateWidth,
measuredHeight
)))
computedCandidatesWidthPx = tmpWidthPx
}
}
val widthToIncreasePerItem = (measuredWidth - computedCandidatesWidthPx) / computedCandidates.size
for (n in computedCandidates.indices) {
computedCandidates[n].geometry.let {
it.left += n * widthToIncreasePerItem
it.right += (n + 1) * widthToIncreasePerItem
}
}
}
DisplayMode.DYNAMIC_SCROLLABLE -> {
if (clipItemAvailable) {
val candidateWidth = (textPaint.measureText(clipItem!!.stringRepresentation()).toInt() + candidateMarginH + measuredHeight * 4 / 6).coerceAtMost(maxDynamicCandidateWidth)
computedCandidates.add(ComputedCandidate.Clip(clipItem, Rect(
0,
0,
candidateWidth,
measuredHeight
)))
computedCandidatesWidthPx += candidateWidth
}
for (n in candidates.indices) {
if (computedCandidatesWidthPx > 0) {
computedCandidatesWidthPx += dividerWidth
}
val candidateWidth = (textPaint.measureText(candidates[n]).toInt() + 2 * candidateMarginH).coerceAtMost(maxDynamicCandidateWidth)
computedCandidates.add(ComputedCandidate.Word(candidates[n], Rect(
computedCandidatesWidthPx,
0,
computedCandidatesWidthPx + candidateWidth,
measuredHeight
)))
computedCandidatesWidthPx += candidateWidth
}
}
}
}
selectedIndex = -1
scroller.abortAnimation()
scrollTo(0, 0)
invalidate()
}
override fun computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.currX, scroller.currY)
invalidate()
}
}
private fun determineSelectedIndex(relX: Int, relY: Int): Int {
val absX = relX + scrollX
val absY = relY + scrollY
var retIndex = -1
for ((n, computedCandidate) in computedCandidates.withIndex()) {
if (computedCandidate.geometry.contains(absX, absY)) {
retIndex = n
break
}
}
return retIndex
}
private fun onCandidateClick(index: Int) {
computedCandidates.getOrNull(index)?.let { candidate ->
when (candidate) {
is ComputedCandidate.Word -> {
eventListener.get()?.onSmartbarCandidatePressed(candidate.word)
}
is ComputedCandidate.Clip -> {
eventListener.get()?.onSmartbarClipboardCandidatePressed(candidate.clipboardItem)
}
is ComputedCandidate.Empty -> {
}
}
}
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
super.onTouchEvent(event)
event ?: return false
return when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
isPressed = true
selectedIndex = determineSelectedIndex(event.x.toInt(), event.y.toInt())
if (displayMode == DisplayMode.DYNAMIC_SCROLLABLE) {
velocityTracker?.recycle()
velocityTracker = VelocityTracker.obtain()
velocityTracker?.addMovement(event)
lastX = event.x
}
invalidate()
true
}
MotionEvent.ACTION_MOVE -> when (displayMode) {
DisplayMode.CLASSIC,
DisplayMode.DYNAMIC -> {
computedCandidates.getOrNull(selectedIndex)?.let { candidate ->
if (!candidate.geometry.contains(scrollX + event.x.toInt(), scrollY + event.y.toInt())) {
selectedIndex = -1
invalidate()
}
}
true
}
DisplayMode.DYNAMIC_SCROLLABLE -> {
velocityTracker?.addMovement(event)
selectedIndex = -1
if (computedCandidatesWidthPx > measuredWidth) {
scrollTo((scrollX + lastX - event.x).toInt().coerceIn(0, computedCandidatesWidthPx - measuredWidth), 0)
lastX = event.x
}
invalidate()
true
}
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
isPressed = false
if (event.actionMasked == MotionEvent.ACTION_UP) {
onCandidateClick(selectedIndex)
}
selectedIndex = -1
if (displayMode == DisplayMode.DYNAMIC_SCROLLABLE) {
velocityTracker?.let {
it.addMovement(event)
it.computeCurrentVelocity(1000)
if (computedCandidatesWidthPx > measuredWidth) {
scroller.fling(
scrollX, 0,
-it.xVelocity.toInt(), 0,
0, computedCandidatesWidthPx - measuredWidth,
0, 0,
0, 0
)
}
it.recycle()
velocityTracker = null
}
}
invalidate()
true
}
else -> false
}
}
override fun onThemeUpdated(theme: Theme) {
candidateBackground = theme.getAttr(Theme.Attr.WINDOW_SEMI_TRANSPARENT_COLOR)
candidateForeground = theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND)
dividerBackground = theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND_ALT)
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas ?: return
backgroundPaint.apply { color = candidateBackground.toSolidColor().color }
dividerPaint.apply { color = ColorUtils.setAlphaComponent(dividerBackground.toSolidColor().color, 64) }
textPaint.apply { color = candidateForeground.toSolidColor().color }
for ((n, computedCandidate) in computedCandidates.withIndex()) {
with(computedCandidate) {
if (n == selectedIndex) {
canvas.drawRect(geometry, backgroundPaint)
}
when (this) {
is ComputedCandidate.Word -> {
val ellipsizedWord = TextUtils.ellipsize(
word, textPaint, geometry.width().toFloat() - candidateMarginH, TextUtils.TruncateAt.MIDDLE
).toString()
canvas.drawText(
ellipsizedWord,
geometry.left + geometry.width() / 2.0f,
geometry.top + geometry.height() / 2.0f - (textPaint.descent() + textPaint.ascent()) / 2.0f,
textPaint
)
}
is ComputedCandidate.Clip -> {
pasteDrawable?.setTint(candidateForeground.toSolidColor().color)
pasteDrawable?.setBounds(
geometry.left + geometry.height() / 3,
geometry.height() / 3,
geometry.left + geometry.height() * 2 / 3,
geometry.height() * 2 / 3
)
pasteDrawable?.draw(canvas)
val pdWidth = geometry.height().toFloat()
val ellipsizedWord = TextUtils.ellipsize(
clipboardItem.stringRepresentation(), textPaint, geometry.width().toFloat() - pdWidth, TextUtils.TruncateAt.MIDDLE
).toString()
canvas.drawText(
ellipsizedWord,
geometry.left + geometry.width() / 2.0f + pdWidth / 2.0f - candidateMarginH,
geometry.top + geometry.height() / 2.0f - (textPaint.descent() + textPaint.ascent()) / 2.0f,
textPaint
)
}
is ComputedCandidate.Empty -> {
}
}
if (n + 1 < computedCandidates.size) {
canvas.drawRect(
geometry.right.toFloat(),
(geometry.height() / 4).toFloat(),
(geometry.right + dividerWidth).toFloat(),
(geometry.height() * 3 / 4).toFloat(),
dividerPaint
)
}
}
}
}
/**
* Data class describing a computed candidate item.
*
* @property geometry The geometry of the computed candidate, used to position and size the item correctly when
* being drawn on a canvas.
*/
private sealed class ComputedCandidate(val geometry: Rect) {
/**
* Computed word candidate, used for suggestions provided by the NLP algorithm.
*
* @property word The word this computed candidate item represents. Used in the callback to provide which word
* should be filled out.
*/
class Word(
val word: String,
geometry: Rect
) : ComputedCandidate(geometry) {
override fun toString(): String {
return "Word { word=\"$word\", geometry=$geometry }"
}
}
/**
* Computed word candidate, used for filling space when [DisplayMode.CLASSIC] is active. Does not hold any data
* and also does nothing when clicked on.
*/
class Empty(
geometry: Rect
) : ComputedCandidate(geometry) {
override fun toString(): String {
return "Empty { geometry=$geometry }"
}
}
/**
* Computed word candidate, used for clipboard paste suggestions.
*
* @property clipboardItem The clipboard item this computed candidate item represents. Used in the callback to
* provide which item should be pasted.
*/
class Clip(
val clipboardItem: ClipboardItem,
geometry: Rect
) : ComputedCandidate(geometry) {
override fun toString(): String {
return "Clip { clipboardItem=$clipboardItem, geometry=$geometry }"
}
}
}
/**
* Enum class defining the display mode for the candidate view.
*/
enum class DisplayMode {
CLASSIC,
DYNAMIC,
DYNAMIC_SCROLLABLE;
companion object {
fun fromString(string: String): DisplayMode {
return valueOf(string.toUpperCase(Locale.ENGLISH))
}
}
override fun toString(): String {
return super.toString().toLowerCase(Locale.ENGLISH)
}
}
}

View File

@@ -19,12 +19,12 @@ package dev.patrickgold.florisboard.ime.text.smartbar
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.Button
import androidx.annotation.IdRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.children
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.databinding.SmartbarBinding
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.PrefHelper
import dev.patrickgold.florisboard.ime.core.Subtype
@@ -32,8 +32,6 @@ import dev.patrickgold.florisboard.ime.text.key.KeyVariation
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.util.setBackgroundTintColor2
import dev.patrickgold.florisboard.util.setDrawableTintColor2
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
@@ -51,7 +49,7 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
private val themeManager = ThemeManager.default()
private var eventListener: WeakReference<EventListener?>? = null
private var eventListener: WeakReference<EventListener?> = WeakReference(null)
private val mainScope = MainScope()
private var lastSuggestionInitDate: Long = 0
@@ -66,15 +64,12 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
binding.quickActionToggle.rotation = if (v) 180.0f else 0.0f
field = v
}
private var shouldSuggestClipboardContents: Boolean = false
private lateinit var binding: SmartbarBinding
private var indexedActionStartArea: MutableList<Int> = mutableListOf()
private var indexedMainArea: MutableList<Int> = mutableListOf()
private var indexedActionEndArea: MutableList<Int> = mutableListOf()
private var candidateViewList: MutableList<Button> = mutableListOf()
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
@@ -102,11 +97,9 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
indexedActionEndArea.add(view.id)
}
candidateViewList.add(binding.candidate0)
candidateViewList.add(binding.candidate1)
candidateViewList.add(binding.candidate2)
binding.backButton.setOnClickListener { eventListener.get()?.onSmartbarBackButtonPressed() }
binding.backButton.setOnClickListener { eventListener?.get()?.onSmartbarBackButtonPressed() }
binding.candidates.updateDisplaySettings(prefs.suggestion.displayMode, prefs.suggestion.clipboardContentTimeout * 1_000)
mainScope.launch(Dispatchers.Default) {
florisboard?.let {
@@ -122,28 +115,6 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
}
}
binding.candidate0.setOnClickListener {
if (it is Button) {
eventListener?.get()?.onSmartbarCandidatePressed(it.text.toString())
}
}
binding.candidate1.setOnClickListener {
if (it is Button) {
eventListener?.get()?.onSmartbarCandidatePressed(it.text.toString())
}
}
binding.candidate2.setOnClickListener {
if (it is Button) {
eventListener?.get()?.onSmartbarCandidatePressed(it.text.toString())
}
}
binding.clipboardSuggestion.setOnClickListener {
florisboard?.activeEditorInstance?.performClipboardPaste()
shouldSuggestClipboardContents = false
updateSmartbarState()
}
mainScope.launch(Dispatchers.Default) {
florisboard?.let {
val layout = it.textInputManager.layoutManager.fetchComputedLayoutAsync(
@@ -159,13 +130,13 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
}
binding.privateModeButton.setOnClickListener {
eventListener?.get()?.onSmartbarPrivateModeButtonClicked()
eventListener.get()?.onSmartbarPrivateModeButtonClicked()
}
for (quickAction in binding.quickActions.children) {
if (quickAction is SmartbarQuickActionButton) {
quickAction.id.let { quickActionId ->
quickAction.setOnClickListener { eventListener?.get()?.onSmartbarQuickActionPressed(quickActionId) }
quickAction.setOnClickListener { eventListener.get()?.onSmartbarQuickActionPressed(quickActionId) }
}
}
}
@@ -189,7 +160,6 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
}
override fun onDetachedFromWindow() {
eventListener = null
florisboard?.textInputManager?.unregisterSmartbarView(this)
themeManager.unregisterOnThemeUpdatedListener(this)
super.onDetachedFromWindow()
@@ -248,6 +218,7 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
*/
fun updateSmartbarState() {
binding.clipboardCursorRow.updateVisibility()
binding.candidates.updateDisplaySettings(prefs.suggestion.displayMode, prefs.suggestion.clipboardContentTimeout * 1_000)
when (florisboard) {
null -> configureFeatureVisibility(
actionStartAreaVisible = false,
@@ -275,10 +246,6 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
KeyboardMode.PHONE,
KeyboardMode.PHONE2 -> null
else -> when {
florisboard.activeEditorInstance.isComposingEnabled &&
shouldSuggestClipboardContents &&
florisboard.activeEditorInstance.selection.isCursorMode
-> R.id.clipboard_suggestion_row
florisboard.activeEditorInstance.isComposingEnabled &&
florisboard.activeEditorInstance.selection.isCursorMode
-> R.id.candidates
@@ -300,50 +267,21 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
}
fun onPrimaryClipChanged() {
if (prefs.suggestion.enabled && prefs.suggestion.suggestClipboardContent &&
florisboard?.activeEditorInstance?.isPrivateMode == false) {
shouldSuggestClipboardContents = true
val item = florisboard.clipboardManager?.primaryClip?.getItemAt(0)
when {
item?.text != null -> {
binding.clipboardSuggestion.text = item.text
}
item?.uri != null -> {
binding.clipboardSuggestion.text = "(Image) " + item.uri.toString()
}
else -> {
binding.clipboardSuggestion.text = item?.text ?: "(Error while retrieving clipboard data)"
}
}
if (prefs.suggestion.enabled && prefs.suggestion.clipboardContentEnabled && florisboard?.activeEditorInstance?.isPrivateMode == false ) {
florisboard.florisClipboardManager?.primaryClip?.let { binding.candidates.updateClipboardItem(it) }
updateSmartbarState()
}
}
fun resetClipboardSuggestion() {
shouldSuggestClipboardContents = false
updateSmartbarState()
}
fun setCandidateSuggestionWords(suggestionInitDate: Long, suggestions: List<String>) {
fun setCandidateSuggestionWords(suggestionInitDate: Long, suggestions: List<String>?) {
if (suggestionInitDate > lastSuggestionInitDate) {
lastSuggestionInitDate = suggestionInitDate
binding.candidate1.text = suggestions.getOrNull(0) ?: ""
binding.candidate0.text = suggestions.getOrNull(1) ?: ""
binding.candidate2.text = suggestions.getOrNull(2) ?: ""
binding.candidates.updateCandidates(suggestions)
}
}
fun updateCandidateSuggestionCapsState() {
val tim = florisboard?.textInputManager ?: return
if (tim.capsLock) {
binding.candidate0.text = binding.candidate0.text.toString().toUpperCase(florisboard.activeSubtype.locale)
binding.candidate1.text = binding.candidate1.text.toString().toUpperCase(florisboard.activeSubtype.locale)
binding.candidate2.text = binding.candidate2.text.toString().toUpperCase(florisboard.activeSubtype.locale)
} else {
binding.candidate0.text = binding.candidate0.text.toString().toLowerCase(florisboard.activeSubtype.locale)
binding.candidate1.text = binding.candidate1.text.toString().toLowerCase(florisboard.activeSubtype.locale)
binding.candidate2.text = binding.candidate2.text.toString().toLowerCase(florisboard.activeSubtype.locale)
}
//
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
@@ -369,17 +307,12 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
override fun onThemeUpdated(theme: Theme) {
setBackgroundColor(theme.getAttr(Theme.Attr.SMARTBAR_BACKGROUND).toSolidColor().color)
setBackgroundTintColor2(binding.clipboardSuggestion, theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_BACKGROUND).toSolidColor().color)
setDrawableTintColor2(binding.clipboardSuggestion, theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_FOREGROUND).toSolidColor().color)
binding.clipboardSuggestion.setTextColor(theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_FOREGROUND).toSolidColor().color)
for (view in candidateViewList) {
view.setTextColor(theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND).toSolidColor().color)
}
invalidate()
}
fun setEventListener(listener: EventListener) {
eventListener = WeakReference(listener)
binding.candidates.setEventListener(listener)
}
/**
@@ -389,6 +322,7 @@ class SmartbarView : ConstraintLayout, ThemeManager.OnThemeUpdatedListener {
interface EventListener {
fun onSmartbarBackButtonPressed() {}
fun onSmartbarCandidatePressed(word: String) {}
fun onSmartbarClipboardCandidatePressed(clipboardItem: ClipboardItem) {}
//fun onSmartbarCandidateLongPressed() {}
fun onSmartbarPrivateModeButtonClicked() {}
fun onSmartbarQuickActionPressed(@IdRes quickActionId: Int) {}

View File

@@ -58,10 +58,10 @@ class ThemeManager private constructor(
private set
companion object {
/**
* The static relative path where a theme is located, regardless of the [AssetSource].
*/
/** The static relative path where a theme is located, regardless of the [AssetSource]. */
const val THEME_PATH_REL: String = "ime/theme"
/** Maximum size in bytes a theme file may have when loaded. */
const val THEME_MAX_SIZE: Int = 512_000
private var defaultInstance: ThemeManager? = null
@@ -94,7 +94,7 @@ class ThemeManager private constructor(
}
/**
* Updates the current theme ref and loads the corresponding theme, as well as notfies all
* Updates the current theme ref and loads the corresponding theme, as well as notifies all
* callback receivers about the new theme.
*/
fun update() {
@@ -254,25 +254,21 @@ class ThemeManager private constructor(
}
fun loadTheme(ref: AssetRef): Result<Theme> {
assetManager.loadAsset(ref, ThemeJson::class).onSuccess { themeJson ->
val theme = themeJson.toTheme()
return Result.success(theme)
}.onFailure {
val themeJson = assetManager.loadAsset(ref, ThemeJson::class).getOrElse {
Timber.e(it.toString())
return Result.failure(it)
}
return Result.failure(Exception("Unreachable code"))
val theme = themeJson.toTheme()
return Result.success(theme)
}
fun loadTheme(uri: Uri): Result<Theme> {
assetManager.loadAsset(uri, ThemeJson::class).onSuccess { themeJson ->
val theme = themeJson.toTheme()
return Result.success(theme)
}.onFailure {
val themeJson = assetManager.loadAsset(uri, ThemeJson::class, THEME_MAX_SIZE).getOrElse {
Timber.e(it.toString())
return Result.failure(it)
}
return Result.failure(Exception("Unreachable code"))
val theme = themeJson.toTheme()
return Result.success(theme)
}
fun writeTheme(ref: AssetRef, theme: Theme): Result<Unit> {

View File

@@ -17,7 +17,9 @@
package dev.patrickgold.florisboard.ime.theme
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import androidx.annotation.ColorInt
import dev.patrickgold.florisboard.R
/**
@@ -32,16 +34,22 @@ sealed class ThemeValue {
*/
data class Reference(val group: String, val attr: String) : ThemeValue() {
override fun toString(): String {
return super.toString()
return "@$group/$attr"
}
}
/**
* This holds a solid color as a color int.
*/
data class SolidColor(val color: Int) : ThemeValue() {
data class SolidColor(@ColorInt val color: Int) : ThemeValue() {
companion object {
val TRANSPARENT = SolidColor(Color.TRANSPARENT)
val BLACK = SolidColor(Color.BLACK)
val WHITE = SolidColor(Color.WHITE)
}
override fun toString(): String {
return super.toString()
return "#" + String.format("%08X", color)
}
fun complimentaryTextColor(isAlt: Boolean = false): SolidColor {
@@ -71,7 +79,7 @@ sealed class ThemeValue {
*/
data class LinearGradient(val dummy: Int) : ThemeValue() {
override fun toString(): String {
return super.toString()
return "--undefined--"
}
}
@@ -80,7 +88,7 @@ sealed class ThemeValue {
*/
data class RadialGradient(val dummy: Int) : ThemeValue() {
override fun toString(): String {
return super.toString()
return "--undefined--"
}
}
@@ -89,7 +97,7 @@ sealed class ThemeValue {
*/
data class OnOff(val state: Boolean) : ThemeValue() {
override fun toString(): String {
return super.toString()
return state.toString()
}
}
@@ -99,7 +107,7 @@ sealed class ThemeValue {
*/
data class Other(val rawValue: String) : ThemeValue() {
override fun toString(): String {
return super.toString()
return rawValue
}
}
@@ -172,32 +180,6 @@ sealed class ThemeValue {
}
}
/**
* Converts this theme value to a string representation.
*/
override fun toString(): String {
return when (this) {
is Reference -> {
"@$group/$attr"
}
is SolidColor -> {
"#" + String.format("%08X", color)
}
is LinearGradient -> {
"--undefined--"
}
is RadialGradient -> {
"--undefined--"
}
is OnOff -> {
state.toString()
}
is Other -> {
rawValue
}
}
}
/**
* Converts this theme value to a string representation which can be shown to the user.
*/

View File

@@ -67,7 +67,7 @@ class ThemeManagerActivity : FlorisActivity<ThemeManagerActivityBinding>() {
}
private val importTheme = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
// If uri is null it indicates that the selection activity was cancelled (mostly by pressing the back button,
// If uri is null it indicates that the selection activity was cancelled (mostly by pressing the back button),
// so we don't display an error message here.
if (uri == null) return@registerForActivityResult
val toBeImportedTheme = themeManager.loadTheme(uri)

View File

@@ -33,7 +33,7 @@ class EnableImeFragment : Fragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
binding = SetupFragmentEnableImeBinding.inflate(inflater, container, false)
binding.languageAndInputButton.setOnClickListener {
val intent = Intent()

View File

@@ -30,7 +30,7 @@ class FinishFragment : Fragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
): View {
binding = SetupFragmentFinishBinding.inflate(inflater, container, false)
// Set theme to floris_day

View File

@@ -35,7 +35,7 @@ object LocaleUtils {
}
}
class JsonAdapter() {
class JsonAdapter {
@FromJson
fun fromJson(raw: String): Locale {
return stringToLocale(raw)

View 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="?android:attr/textColorPrimary" android:pathData="M7 15h7v2H7zm0-4h10v2H7zm0-4h10v2H7zm12-4h-4.18C14.4 1.84 13.3 1 12 1c-1.3 0-2.4.84-2.82 2H5c-.14 0-.27.01-.4.04-.39.08-.74.28-1.01.55-.18.18-.33.4-.43.64-.1.23-.16.49-.16.77v14c0 .27.06.54.16.78s.25.45.43.64c.27.27.62.47 1.01.55.13.02.26.03.4.03h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7-.25c.41 0 .75.34.75.75s-.34.75-.75.75-.75-.34-.75-.75.34-.75.75-.75zM19 19H5V5h14v14z"/>
</vector>

View 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="?android:attr/textColorPrimary" android:pathData="M5 13h14v-2H5v2zm-2 4h14v-2H3v2zM7 7v2h14V7H7z"/>
</vector>

View File

@@ -0,0 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24"
android:autoMirrored="true">
<path android:fillColor="?android:attr/textColorPrimary" android:pathData="M14,4v5c0,1.12,0.37,2.16,1,3H9c0.65-0.86,1-1.9,1-3V4H14 M17,2H7C6.45,2,6,2.45,6,3c0,0.55,0.45,1,1,1c0,0,0,0,0,0l1,0v5 c0,1.66-1.34,3-3,3v2h5.97v7l1,1l1-1v-7H19v-2c0,0,0,0,0,0c-1.66,0-3-1.34-3-3V4l1,0c0,0,0,0,0,0c0.55,0,1-0.45,1-1 C18,2.45,17.55,2,17,2L17,2z"/>
</vector>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Bottom 2dp Shadow -->
<item>
<shape android:shape="rectangle">
<solid android:color="@color/cardview_shadow_start_color" />
<corners android:radius="7dp" />
</shape>
</item>
<!-- White Top color -->
<item android:right="3px" android:bottom="5px">
<shape android:shape="rectangle">
<corners android:radius="7dp" />
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<dev.patrickgold.florisboard.ime.clip.ClipboardPopupView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/pin_clip_item"
android:orientation="horizontal"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/pin_clip_item_icon"
android:layout_width="wrap_content"
android:scaleX="0.8"
android:scaleY="0.8"
android:layout_height="wrap_content"
android:src="@drawable/ic_pin"
android:contentDescription="@string/clip__pin_item" />
<Space
android:layout_width="10dp"
android:layout_height="0dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/clip__pin_item"
android:id="@+id/pin_clip_item_text"
tools:layout_editor_absoluteY="3dp" />
</LinearLayout>
<Space
android:layout_width="0dp"
android:layout_height="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/remove_from_history"
android:orientation="horizontal"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/remove_from_history_icon"
android:layout_width="wrap_content"
android:scaleX="0.8"
android:scaleY="0.8"
android:layout_height="wrap_content"
android:src="@drawable/ic_delete"
android:contentDescription="@string/clip__delete_item" />
<Space
android:layout_width="10dp"
android:layout_height="0dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/clip__delete_item"
android:id="@+id/remove_from_history_text"
tools:layout_editor_absoluteY="3dp" />
</LinearLayout>
<Space
android:id="@+id/paste_clip_item_space"
android:layout_width="0dp"
android:layout_height="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:id="@+id/paste_clip_item"
android:orientation="horizontal"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/paste_clip_item_icon"
android:layout_width="wrap_content"
android:scaleX="0.8"
android:scaleY="0.8"
android:layout_height="wrap_content"
android:src="@drawable/ic_content_paste"
android:contentDescription="@string/clip__paste_item" />
<Space
android:layout_width="10dp"
android:layout_height="0dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/clip__paste_item"
android:id="@+id/paste_clip_item_text"
tools:layout_editor_absoluteY="3dp" />
</LinearLayout>
</dev.patrickgold.florisboard.ime.clip.ClipboardPopupView>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<dev.patrickgold.florisboard.ime.clip.ClipboardHistoryItemView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="0dp"
android:background="@drawable/shape_rect_rounded_3"
android:foreground="?selectableItemBackground"
>
<ImageView
android:id="@+id/clipboard_history_item_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_marginEnd="0dp"
android:padding="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@drawable/shape_rect_rounded_3"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/clipboard_pin"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/ic_pin"
android:contentDescription="@string/clip__pin_item"/>
</dev.patrickgold.florisboard.ime.clip.ClipboardHistoryItemView>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<dev.patrickgold.florisboard.ime.clip.ClipboardHistoryItemView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="5dp"
android:foreground="?selectableItemBackground"
android:background="@drawable/shape_rect_rounded_3"
>
<TextView
android:id="@+id/clipboard_history_item_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="25dp"
android:padding="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="A clipboard item would go here." />
<ImageView
android:id="@+id/clipboard_pin"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginEnd="5dp"
android:layout_marginTop="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/ic_pin"
android:contentDescription="@string/clip__pin_item"/>
</dev.patrickgold.florisboard.ime.clip.ClipboardHistoryItemView>

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<dev.patrickgold.florisboard.ime.clip.ClipboardHistoryView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/clip_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/clipboard_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="@+id/back_to_keyboard_button"
android:layout_width="@dimen/clipboard_button_width"
android:layout_height="@dimen/clipboard_button_height"
android:layout_gravity="center_vertical"
android:background="@drawable/button_transparent_bg_on_press"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:layout_weight="0"
android:src="@drawable/ic_arrow_back"
android:contentDescription="@string/clip__back_to_text_input" />
<TextView
android:id="@+id/clipboard_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_weight="1"
android:text="@string/clip__context_header"
android:textSize="15sp" />
<ImageButton
android:id="@+id/clear_clipboard_history"
android:layout_width="@dimen/clipboard_button_width"
android:layout_height="@dimen/clipboard_button_height"
android:layout_gravity="center_vertical"
android:background="@drawable/button_transparent_bg_on_press"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:layout_weight="0"
android:src="@drawable/ic_clear_all"
android:contentDescription="@string/clip__clear_history" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/clipboard_history_items"
android:paddingLeft="5dp"
android:paddingRight="5dp"
/>
</LinearLayout>
</dev.patrickgold.florisboard.ime.clip.ClipboardHistoryView>

View File

@@ -57,6 +57,8 @@
<include layout="@layout/media_input_layout"/>
<include layout="@layout/clipboard_layout"/>
</dev.patrickgold.florisboard.ime.core.FlorisViewFlipper>
<dev.patrickgold.florisboard.ime.onehanded.OneHandedPanel

View File

@@ -39,38 +39,9 @@
app:layout_constraintEnd_toStartOf="@id/action_end_area"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
<dev.patrickgold.florisboard.ime.text.smartbar.CandidateView
android:id="@+id/candidates"
style="@style/SmartbarContainer">
<Button
android:id="@+id/candidate0"
style="@style/SmartbarCandidate"/>
<View style="@style/SmartbarDivider"/>
<Button
android:id="@+id/candidate1"
style="@style/SmartbarCandidate"/>
<View style="@style/SmartbarDivider"/>
<Button
android:id="@+id/candidate2"
style="@style/SmartbarCandidate"/>
</LinearLayout>
<LinearLayout
android:id="@+id/clipboard_suggestion_row"
style="@style/SmartbarContainer">
<Button
android:id="@+id/clipboard_suggestion"
android:drawableStart="@drawable/ic_content_paste_with_padding"
style="@style/SmartbarQuickAction.ClipboardSuggestion"/>
</LinearLayout>
style="@style/SmartbarContainer"/>
<LinearLayout
android:id="@+id/quick_actions"

View File

@@ -92,11 +92,19 @@
<string name="settings__theme_editor__add_group_dialog_title" comment="Title of the add group dialog in the theme editor">إضافة مجموعة</string>
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">تحرير المجموعة</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">اضافة الخاصيه</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">المرجع</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">مجموعة</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">الخاصية</string>
<string name="settings__theme_editor__value_type_solid_color" comment="Theme value type">لون كامل</string>
<string name="settings__theme_editor__value_type_lin_grad" comment="Theme value type">تدرّج خطي</string>
<string name="settings__theme_editor__value_type_rad_grad" comment="Theme value type">تدرّج شعاعي</string>
<string name="settings__theme_editor__value_type_on_off" comment="Theme value type">تبديل</string>
<string name="settings__theme_editor__value_type_on_off_state" comment="Theme value type sub-field">الحالة</string>
<string name="settings__theme_editor__value_type_other" comment="Theme value type">أخرى</string>
<string name="settings__theme_editor__value_type_other_text" comment="Theme value type sub-field">النص</string>
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">يرجى ادخال اسم المظهر.</string>
<string name="settings__theme_editor__error_group_name_empty" comment="Error text for an empty group name">الرجاء إدخال اسم المجموعة.</string>
<string name="settings__theme_editor__error_attr_name_empty" comment="Error text for an empty attribute name">الرجاء إدخال اسم الخاصية.</string>
<string name="settings__theme__group_window" comment="Theme group label">النافذة والنظام</string>
<string name="settings__theme__group_keyboard" comment="Theme group label">لوحة المفاتيح</string>
<string name="settings__theme__group_key" comment="Theme group label">المفتاح</string>
@@ -105,10 +113,17 @@
<string name="settings__theme__group_popup" comment="Theme group label">نافذة منبثقة</string>
<string name="settings__theme__group_privateMode" comment="Theme group label">الوضع الخاص</string>
<string name="settings__theme__group_smartbar" comment="Theme group label">الشريط الذكـي</string>
<string name="settings__theme__group_smartbarButton" comment="Theme group label">زر الشريط الذكي</string>
<string name="settings__theme__group_custom" comment="Theme group label (%s is custom group name)">مجموعات مخصصة (%s)</string>
<string name="settings__theme__attr_background" comment="Theme attribute label">لون الخلفية</string>
<string name="settings__theme__attr_foreground" comment="Theme attribute label">لون الواجهة</string>
<string name="settings__theme__attr_showBorder" comment="Theme attribute label">عرض الحدود</string>
<string name="settings__theme__attr_colorPrimary" comment="Theme attribute label">اللون الأساسي</string>
<string name="settings__theme__attr_colorPrimaryDark" comment="Theme attribute label">اللون الأساسي (داكن)</string>
<string name="settings__theme__attr_colorAccent" comment="Theme attribute label">لون التمييز</string>
<string name="settings__theme__attr_navBarColor" comment="Theme attribute label">لون شريط التصفّح</string>
<string name="settings__theme__attr_navBarLight" comment="Theme attribute label">الواجهة الداكنة لشريط التصفّح</string>
<string name="settings__theme__attr_semiTransparentColor" comment="Theme attribute label">لون شبه شفاف</string>
<string name="settings__theme__attr_textColor" comment="Theme attribute label">لون النص</string>
<string name="settings__keyboard__title" comment="Title of Keyboard preferences fragment">تفضيلات لوحة المفاتيح</string>
<string name="pref__keyboard__group_keys__label" comment="Preference group title">المفاتيح</string>
@@ -120,15 +135,18 @@
<string name="pref__keyboard__hint_mode__enabled_hint_priority" comment="Preference value">مفعّل (الأولوية للتلميح)</string>
<string name="pref__keyboard__hint_mode__enabled_accent_priority" comment="Preference value">مفعّل (الأولوية للحروف الإضافية)</string>
<string name="pref__keyboard__hint_mode__enabled_smart_priority" comment="Preference value">مفعّل (تحديد الأولويات الذكي)</string>
<string name="pref__keyboard__utility_key_action__switch_to_emojis" comment="Preference value">الإنتقال إلى الإيموجيز</string>
<string name="pref__keyboard__utility_key_action__switch_language" comment="Preference value">تغيير اللغة</string>
<string name="pref__keyboard__utility_key_action__switch_keyboard_app" comment="Preference value">تبديل تطبيق لوحة المفاتيح</string>
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">مضاعف حجم الخط (عمودي)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">وضع اليد الواحدة</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">وضع اليد الواحدة</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">إيقاف</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">وضع اليد اليمنى</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">وضع اليد اليسرى</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">عدم الاظهار أبداً</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">الإظهار دائماً</string>
<string name="pref__keyboard__height_factor__label" comment="Preference title">ارتفاع لوحة المفاتيح</string>
<string name="pref__keyboard__height_factor__extra_short" comment="Preference value">قصير جدا</string>
<string name="pref__keyboard__height_factor__short" comment="Preference value">قصير</string>
@@ -227,7 +245,9 @@
<string name="assets__action__no">كلا</string>
<string name="assets__action__save">حفظ</string>
<string name="assets__action__yes">موافق</string>
<string name="assets__error__details">التفاصيل</string>
<string name="assets__error__invalid">غير صحيح</string>
<string name="assets__error__snackbar_message">لقد حدث خطأ ما</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">الإعداد</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">السابق</string>
@@ -261,4 +281,10 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">انقر لعرض تفاصيل الخطأ</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">يبدو أن FlorisBoard يوقف عن العمل بشكل متكرر…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">العودة إلى لوحة المفاتيح السابقة لإيقاف حلقة التعطل الغير منتهية. انقر لعرض تفاصيل الخطأ</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">الإنتقال إلى سجل الحافظة</string>
<string name="clip__context_header">سجل الحافظة</string>
<string name="clip__clear_history">مسح السجل</string>
<string name="clip__delete_item">حذف</string>
<string name="clip__paste_item">لصق</string>
</resources>

View File

@@ -5,7 +5,7 @@
<string name="key__phone_wait" comment="Label for the Wait key in the telephone keyboard layout">Изчакване</string>
<string name="key_popup__threedots_alt" comment="Content description for the three-dots icon in a key popup">Икона с три точки. Ако е видима, означава, че при по-продължително натискане могат да се използват повече букви.</string>
<!-- One-handed strings -->
<string name="one_handed__close_btn_content_description" comment="Content description for the one-handed close button">Излиза от режим за една ръка.</string>
<string name="one_handed__close_btn_content_description" comment="Content description for the one-handed close button">Излиза от режим за работа с една ръка.</string>
<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>
<!-- Private mode info dialog strings -->
@@ -30,7 +30,7 @@
<!-- 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>
<string name="smartbar__quick_action__one_handed_mode" comment="Content-description for the one-handed quick action in Smartbar">Превключва режима за работа с една ръка.</string>
<string name="smartbar__quick_action__one_handed_mode" comment="Content-description for the one-handed quick action 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>
@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Създаване от избрана тема</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Персонализирано (базирано на %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Нова тема</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Темата е внесена успешно!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Темата е изнесена успешно!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Редактиране на тема</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Име</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Вид</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Редактиране на група</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Добавяне на атрибут</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Редактиране на атрибут</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Промяна на име на тема</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Референция</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Група</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Атрибут</string>
@@ -108,16 +111,16 @@
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">Въведете име на темата.</string>
<string name="settings__theme_editor__error_group_name" comment="Error text for an invalid group name">Моля, въведете име на група, която съдържа само букви (aя и/или AЯ), двоеточия (:) за подгрупиране или допълнително числа (09), тилда (~) и подчертаване (_) за етикета на клавиша.</string>
<string name="settings__theme_editor__error_group_name_empty" comment="Error text for an empty group name">Въведете име на групата.</string>
<string name="settings__theme_editor__error_group_name_already_exists" comment="Error text for a duplicate group name">Група с това име вече съществува в темата. Посочете друго.</string>
<string name="settings__theme_editor__error_group_name_already_exists" comment="Error text for a duplicate group name">Група с такова име вече съществува в темата. Посочете друго.</string>
<string name="settings__theme_editor__error_attr_name" comment="Error text for an invalid attribute name">Въведете име на атрибут, което съдържа само буквите a-я и/или A-Я.</string>
<string name="settings__theme_editor__error_attr_name_empty" comment="Error text for an empty attribute name">Въведете име на атрибут.</string>
<string name="settings__theme_editor__error_attr_name_already_exists" comment="Error text for a duplicate attribute name">Атрибут с това име вече съществува в групата. Посочете друго.</string>
<string name="settings__theme_editor__error_attr_name_already_exists" comment="Error text for a duplicate attribute name">Атрибут с такова име вече съществува в групата. Посочете друго.</string>
<string name="settings__theme__group_window" comment="Theme group label">Прозорец и система</string>
<string name="settings__theme__group_keyboard" comment="Theme group label">Клавиатура</string>
<string name="settings__theme__group_key" comment="Theme group label">Клавиши</string>
<string name="settings__theme__group_key_specific" comment="Theme group label (%s is specific modifier)">Клавиш (%s)</string>
<string name="settings__theme__group_media" comment="Theme group label">Медиен контекст</string>
<string name="settings__theme__group_oneHanded" comment="Theme group label">За една ръка</string>
<string name="settings__theme__group_oneHanded" comment="Theme group label">Работа с една ръка</string>
<string name="settings__theme__group_popup" comment="Theme group label">Изскачащ прозорец</string>
<string name="settings__theme__group_privateMode" comment="Theme group label">Поверителен режим</string>
<string name="settings__theme__group_smartbar" comment="Theme group label">Умна лента</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Множител на размер на шрифта (портрет)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">Режим за работа с една ръка</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Режим за работа с една ръка</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Изключено</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Режим за дясна ръка</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Режим за лява ръка</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__landscape_input_ui_mode__never_show" comment="Preference value">Никога да не се показва</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Винаги да се показва</string>
@@ -177,7 +181,7 @@
<string name="pref__keyboard__height_factor__tall" comment="Preference value">Висока</string>
<string name="pref__keyboard__height_factor__extra_tall" comment="Preference value">Много висока</string>
<string name="pref__keyboard__height_factor__custom" comment="Preference value">Персонализирана</string>
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Персонализирана стойност за височина на клавиатура</string>
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Персонализирана стойност за височина на клавиатурата</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Отстъп отдолу (портрет)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Отстъп отдолу (пейзаж)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Разстояние между клавиши (вертикално)</string>
@@ -190,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Видимост на изскачащ прозорец</string>
<string name="pref__keyboard__popup_visible__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>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Изживяване при въвеждане</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Показване на умна лента</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Показване над първия ред</string>
@@ -284,7 +290,9 @@
<string name="assets__action__no">Не</string>
<string name="assets__action__save">Запазване</string>
<string name="assets__action__yes">Да</string>
<string name="assets__error__details">Подробности</string>
<string name="assets__error__invalid">Невалидно</string>
<string name="assets__error__snackbar_message">Нещо се обърка</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Настройка</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Пред.</string>
@@ -318,4 +326,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Докоснете, за да видите подробности за грешката</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard изглежда спира да работи многократно…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Връщане към предишна клавиатура, за да се спре безкрайния цикъл от сривове. Докоснете, за да видите подробности за грешката</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Превключване към история на буфера</string>
<string name="clip__context_header">История на буферната памет</string>
<string name="clip__clear_history">Изчистване на историята</string>
<string name="clip__unpin_item">Освобождаване на елемент</string>
<string name="clip__pin_item">Закачане на елемент</string>
<string name="clip__delete_item">Изтриване</string>
<string name="clip__paste_item">Поставяне</string>
<string name="clip__back_to_text_input">Към въвеждане на текст</string>
<string name="clip__cant_paste">Приложението не поддържа поставяне на това съдържание.</string>
</resources>

View File

@@ -98,7 +98,7 @@
<string name="pref__keyboard__utility_key_action__switch_language" comment="Preference value">Promijeni jezik</string>
<string name="pref__keyboard__utility_key_action__switch_keyboard_app" comment="Preference value">Promijeni tastaturu</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Raspored</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Mod za jednu ruku</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Mod za jednu ruku</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Isključeno</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Mod za desnu ruku</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Mod za lijevu ruku</string>
@@ -183,4 +183,5 @@
<!-- Crash Dialog strings -->
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">Kopiraj u međuspremnik</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Zatvori</string>
<!-- clipboard strings -->
</resources>

View File

@@ -85,7 +85,10 @@
<string name="settings__theme_manager__title_night" comment="Title of the theme manager activity for night theme">Gestor de temes (nocturn)</string>
<string name="settings__theme_manager__create_empty" comment="Label of the Create empty FAB action">Crear un nou tema</string>
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Crear a partir del tema seleccionat</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Personalitzat (basat en %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Nou tema</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">El tema s\'ha importat correctament!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">El tema s\'ha exportat correctament!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Editar tema</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nom</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Tipus</string>
@@ -93,14 +96,23 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Editar grup</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Afegir un atribut</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Editar atribut</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Editar el nom del tema</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Referència</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Grup</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atribut</string>
<string name="settings__theme_editor__value_type_solid_color" comment="Theme value type">Color sòlid</string>
<string name="settings__theme_editor__value_type_lin_grad" comment="Theme value type">Degradat lineal</string>
<string name="settings__theme_editor__value_type_rad_grad" comment="Theme value type">Degradat radial</string>
<string name="settings__theme_editor__value_type_on_off" comment="Theme value type">Canvia</string>
<string name="settings__theme_editor__value_type_on_off_state" comment="Theme value type sub-field">Estat</string>
<string name="settings__theme_editor__value_type_other" comment="Theme value type">Altres</string>
<string name="settings__theme_editor__value_type_other_text" comment="Theme value type sub-field">Text</string>
<string name="settings__theme_editor__value_preview_content_description" comment="Theme value preview content description">Vista prèvia del valor del tema</string>
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">Introdueix un nom de tema.</string>
<string name="settings__theme_editor__error_group_name" comment="Error text for an invalid group name">Si us plau, introdueix un nom de grup que només contingui lletres (a-z i/o A-Z), columnes (:) per a sub-agrupament o addicionalment nombres (0-9), titlla (~) i guions baixos (_) per a l\'etiqueta de la clau.</string>
<string name="settings__theme_editor__error_group_name_empty" comment="Error text for an empty group name">Si us plau, introdueix un nom de grup.</string>
<string name="settings__theme_editor__error_group_name_already_exists" comment="Error text for a duplicate group name">Aquest nom de grup ja existeix dins d\'aquest tema. Si us plau, escolliu-ne un altre.</string>
<string name="settings__theme_editor__error_attr_name" comment="Error text for an invalid attribute name">Introdueix un nom d\'atribut que només contingui les lletres a-z i/o A-Z.</string>
<string name="settings__theme_editor__error_attr_name_empty" comment="Error text for an empty attribute name">Introduïu un nom d\'atribut.</string>
<string name="settings__theme_editor__error_attr_name_already_exists" comment="Error text for a duplicate attribute name">Aquest nom d\'atribut ja existeix dins d\'aquest grup. Si us plau, especifiqueu-ne un altre.</string>
<string name="settings__theme__group_window" comment="Theme group label">Finestra &amp; Sistema</string>
@@ -113,6 +125,8 @@
<string name="settings__theme__group_privateMode" comment="Theme group label">Mode privat</string>
<string name="settings__theme__group_smartbar" comment="Theme group label">Barra intel·ligent</string>
<string name="settings__theme__group_smartbarButton" comment="Theme group label">Botó de barra intel·ligent</string>
<string name="settings__theme__group_extractEditLayout" comment="Theme group label">Disposició a pantalla completa del paisatge</string>
<string name="settings__theme__group_extractActionButton" comment="Theme group label">Botó d\'acció de pantalla completa del paisatge</string>
<string name="settings__theme__group_custom" comment="Theme group label (%s is custom group name)">Grup personalitzat (%s)</string>
<string name="settings__theme__attr_background" comment="Theme attribute label">Color de fons</string>
<string name="settings__theme__attr_backgroundActive" comment="Theme attribute label">Color de fons (actiu)</string>
@@ -148,11 +162,22 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplicador de la mida del tipus de lletra (vertical)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplicador de la mida de la lletra (horitzontal)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Disposició</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Mode d\'una sola mà</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Mode d\'una sola mà</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Desactivat</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Mode dretà</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Mode esquerrà</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Amplada del teclat en mode una sola ma</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Entrada a pantalla completa del paisatge</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">No mostrar mai</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Mostrar sempre</string>
<string name="pref__keyboard__landscape_input_ui_mode__dynamically_show" comment="Preference value">Mostrar dinàmicament</string>
<string name="pref__keyboard__height_factor__label" comment="Preference title">Alçada del teclat</string>
<string name="pref__keyboard__height_factor__custom" comment="Preference value">Personalitzat</string>
<string name="pref__correction__title" comment="Preference group title">Correccions</string>
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Majúscules automàtiques</string>
<!-- About UI strings -->
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">دروستکردن لە ڕووکارە بەردەستەکان</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">تایبەت (سەرچاوەکراوە لە %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">ڕووکاری نوێ</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">ڕووکار بەسەرکەتوویی هێنرا!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">ڕووکار بەسەرکەتوویی نێردرا!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">ده‌ستکاریکردنی ڕووکار</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">ناو</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">جۆر</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">دەستکاریکردنی گرووپ</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">زیادکردنی تایبەتمەندی</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">دەستکاریکردنی تایبەتمەندی</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">دەستکاریکردنی ناو</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">سەرچاوە</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">گرووپ</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">تایبەتمەندی</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">قەبارەی نووسین (ستوونی)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">بەکارهێنان بە یەک دەست</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">بەکارهێنان بە یەک دەست</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">نا چالاک</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">بەکارهێنان بۆ دەستی ڕاست</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">بەکارهێنان بۆ دەستی چەپ</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__landscape_input_ui_mode__never_show" comment="Preference value">شاردنەوە</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">هەمیشە پیشاندان</string>
@@ -180,6 +184,8 @@
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">ڕێژەی ئاستی قیاسی تەختەکلیل</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">قەبارەی خوارەوە (ستوونی)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">قەبارەی خوارەوە (ئاسۆیی)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">بۆشایی دوگمەکان (ستوونی)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">بۆشایی دوگمەکان (ئاسۆیی)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">کاریگەرییەکان</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">دەنگ لەکاتی نووسین</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">ئاستی دەنگ</string>
@@ -188,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">بچووککراوە پیت</string>
<string name="pref__keyboard__popup_visible__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>
<string name="settings__typing__title" comment="Title of Typing experience fragment">ڕێکخستنەکانی تەختەکلیل</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">پیشاندانی بەشی سەرەوە (SmartBar)</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">پیشاندانی ئامرازەکانی دەستکاریکردنی نووسین لەبەشی سەرەوەی تەختەکلیل</string>
@@ -220,6 +228,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">بردن بۆ لای ڕاست</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">چوون بۆ سەرەتای ڕستە</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">چوون بۆ کۆتایی ڕستە</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">چوون بۆ سەرەتای ڕستە</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">چوون بۆ کۆتایی ڕستە</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">گەورەکردن (Shift) </string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">گۆڕینی تەختەکلیل</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">گۆڕین بۆ تەختەکلیلی پێشوو</string>
@@ -280,7 +290,9 @@
<string name="assets__action__no">نەخێر</string>
<string name="assets__action__save">پاراستن</string>
<string name="assets__action__yes">بەڵێ</string>
<string name="assets__error__details">زانیاری زیاتر</string>
<string name="assets__error__invalid">نا درووستە</string>
<string name="assets__error__snackbar_message">هەڵەیەکی نەزانراو ڕوویدا</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">دامەزراندن</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">پێشتر</string>
@@ -315,4 +327,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">بینینی زانیاری ڕاپۆرتی هەڵە</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">تەختەکلیلی FlorisBoard لەوانەیە زوو زوو لەکارکردن بوەستێت…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">گۆڕین بۆ تەختەکلیلی پێشوو لەکاتی بوونی هەڵە و وەستانی لەناکاو، بینینی زانیاری هەڵەکان</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">گۆڕین بۆ مێژووی لەبەرگیراوەکان</string>
<string name="clip__context_header">لەبەرگیراوەکان</string>
<string name="clip__clear_history">سڕینەوەی مێژوو</string>
<string name="clip__unpin_item">جێگیر نەکردن</string>
<string name="clip__pin_item">جێگیر کردن</string>
<string name="clip__delete_item">سڕینەوە</string>
<string name="clip__paste_item">دانان</string>
<string name="clip__back_to_text_input">گەڕانەوە</string>
<string name="clip__cant_paste">ئەم بەرنامەیە پشتگیری دانانی شتەکان ناکات.</string>
</resources>

View File

@@ -35,6 +35,7 @@
<string name="smartbar__quick_action__switch_to_media_context" comment="Content-description for the media quick action in Smartbar">Přepnout na vkládaní médií.</string>
<string name="smartbar__quick_action__undo" comment="Content-description for the undo quick action in Smartbar">Undo tlačítko pro vrácení poslední akce</string>
<string name="smartbar__quick_action__redo" comment="Content-description for the redo quick action in Smartbar">Redo tlačítko pro obnovení poslední akce</string>
<string name="smartbar__quick_action__private_mode" comment="Content-description for the private mode button in Smartbar">Pokud se zobrazuje, je aktivní soukromý režim. Kliknutím zobrazí informace o soukromém režimu.</string>
<!-- Settings UI strings -->
<string name="settings__title" comment="Title of Settings">Nastavení</string>
<string name="settings__menu" comment="Hint of top-right three-dot icon in Settings">Více možností</string>
@@ -64,6 +65,47 @@
<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__theme__title" comment="Title of the Theme fragment">Motiv klávesnice</string>
<string name="settings__theme__undefined" comment="General string for an undefined preference value">Definován</string>
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Režim motivu</string>
<string name="pref__theme__mode__always_day" comment="Preference value for theme mode">Vždy denní</string>
<string name="pref__theme__mode__always_night" comment="Preference value for theme mode">Vždy noční</string>
<string name="pref__theme__mode__follow_system" comment="Preference value for theme mode">Podle systému</string>
<string name="pref__theme__mode__follow_time" comment="Preference value for theme mode">Podle času</string>
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Čas východu slunce</string>
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Čas západu slunce</string>
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Denní motiv</string>
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Noční motiv</string>
<string name="pref__theme__any_theme__label" comment="Label of the theme selector preference">Vybraný motiv</string>
<string name="pref__theme__any_theme_adapt_to_app__label" comment="Label of the theme adapt to app preference">Přizpůsobit barvy aplikaci</string>
<string name="pref__theme__any_theme_adapt_to_app__summary" comment="Summary of the theme adapt to app preference">Barvy motivu se přizpůsobí barvám používané aplikace, pokud to daná aplikace podporuje.</string>
<string name="pref__theme__source_internal" comment="Label for the theme source field">Interní úložiště</string>
<string name="pref__theme__source_external" comment="Label for the theme source field">Externí poskytovatel</string>
<string name="settings__theme_manager__title_day" comment="Title of the theme manager activity for day theme">Správce motivů (denní)</string>
<string name="settings__theme_manager__title_night" comment="Title of the theme manager activity for night theme">Správce motivů (noční)</string>
<string name="settings__theme_manager__create_empty" comment="Label of the Create empty FAB action">Vytvořit nový motiv</string>
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Vytvořit nový z vybraného motivu</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Vlastní (na základě %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Nový motiv</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Upravit motiv</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Název</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Typ</string>
<string name="settings__theme_editor__add_group_dialog_title" comment="Title of the add group dialog in the theme editor">Přidat skupinu</string>
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Upravit skupinu</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Přidat vlastnost</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Upravit vlastnost</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Odkaz</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Skupina</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atribut</string>
<string name="settings__theme_editor__value_type_solid_color" comment="Theme value type">Jednolitá barva</string>
<string name="settings__theme_editor__value_type_lin_grad" comment="Theme value type">Lineární přechod</string>
<string name="settings__theme_editor__value_type_rad_grad" comment="Theme value type">Radiální přechod</string>
<string name="settings__theme_editor__value_type_on_off" comment="Theme value type">Přepínač</string>
<string name="settings__theme_editor__value_type_on_off_state" comment="Theme value type sub-field">Stav</string>
<string name="settings__theme_editor__value_type_other" comment="Theme value type">Ostatní</string>
<string name="settings__theme_editor__value_type_other_text" comment="Theme value type sub-field">Text</string>
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">Zadejte prosím název motivu.</string>
<string name="settings__theme_editor__error_group_name" comment="Error text for an invalid group name">Prosím, zadejte název skupiny který používá pouze písmena (a-z a/nebo A-Z), dvojtečku (:) pro podskupiny a navíc číslice (0-9), vlnovku (~) a podtržítko (_) pro název klíče.</string>
<string name="settings__theme_editor__error_group_name_empty" comment="Error text for an empty group name">Zadejte název skupiny.</string>
<string name="settings__theme_editor__error_attr_name_empty" comment="Error text for an empty attribute name">Prosím vložte název vlastnosti.</string>
<string name="settings__theme__group_window" comment="Theme group label">Okno &amp; systém</string>
<string name="settings__theme__group_keyboard" comment="Theme group label">Klávesnice</string>
<string name="settings__theme__group_key" comment="Theme group label">Klíč</string>
@@ -74,7 +116,7 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplikátor velikosti písma (portrét)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplikátor velikosti písma (Krajina)</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 value">Režim s jednou rukou</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Režim s jednou rukou</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Z</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Režim pravé ruky</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Režim levé ruky</string>
@@ -188,4 +230,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Klepnutím zobrazíte podrobnosti o chybě</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Zdá se, že FlorisBoard přestal opakovaně pracovat…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Vrácení zpět na předchozí klávesnici pro zastavení nekonečného crash loopu. Klepnutím zobrazíte podrobnosti o chybě</string>
<!-- clipboard strings -->
</resources>

View File

@@ -120,4 +120,5 @@
<string name="setup__finish__title" comment="Title of Setup finished fragment in Setup">Opsætning færdig!</string>
<!-- Crash Dialog strings -->
<string name="crash_dialog__title" comment="Title of crash dialog">FlorisBoard fejl rapport</string>
<!-- clipboard strings -->
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Aus ausgewähltem Design erstellen</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Benutzerdefiniert (basierend auf %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Neues Design</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Design erfolgreich importiert!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Design erfolgreich exportiert!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Design bearbeiten</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Name</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Typ</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Gruppe bearbeiten</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Attribute hinzufügen</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Attribut bearbeiten</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Design Name bearbeiten</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Verweis</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Gruppe</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Attribut</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Schriftgröße anpassen (Hochformat)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Schriftgröße anpassen (Querformat)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Layout</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Einhandmodus</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Einhandmodus</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Aus</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Rechtshändermodus</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Linkshändermodus</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Breite der Tastatur im Einhandmodus</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Querformat Vollbild Eingabe</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Nie zeigen</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Immer zeigen</string>
@@ -180,6 +184,8 @@
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Benutzerdefinierte Tastaturhöhe</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Unterer Versatz (Hochformat)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Unterer Versatz (Querformat)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Platz zwischen Zeichen (vertikal)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">Platz zwischen Zeichen (horizontal)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Tastendruck</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Ton bei Tastendruck</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Lautstärke der Tastendrucktöne</string>
@@ -188,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Pop-Up Sichtbarkeit</string>
<string name="pref__keyboard__popup_visible__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 zurück zur Buchstabenansicht</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>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Tipperlebnis</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>
@@ -220,6 +228,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Cursor nach rechts bewegen</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Cursor an den Zeilenanfang bewegen</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Cursor an das Zeilenende bewegen</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Bewege den Cursor zum Anfang der Seite</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Bewege den Cursor zum Ende der Seite</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Umschalttaste</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Auswahl der Eingabemethode anzeigen</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Zur vorherigen Tastatur wechseln</string>
@@ -280,7 +290,9 @@
<string name="assets__action__no">Nein</string>
<string name="assets__action__save">Speichern</string>
<string name="assets__action__yes">Ja</string>
<string name="assets__error__details">Details</string>
<string name="assets__error__invalid">Ungültig</string>
<string name="assets__error__snackbar_message">Etwas hat nicht geklappt</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Einrichtung</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Zurück</string>
@@ -314,4 +326,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Tippen, um Details anzuzeigen</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard funktioniert zum wiederholten Male nicht…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Um eine endlose Absturzschleife zu verhindern, wurde automatisch auf die zuvor benutzte Tastatur zurückgegriffen. Tippen, um die Fehlermeldung anzuzeigen</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Zum Zwischenablagenverlauf wechseln</string>
<string name="clip__context_header">Zwischenablagenverlauf</string>
<string name="clip__clear_history">Verlauf leeren</string>
<string name="clip__unpin_item">Element lösen</string>
<string name="clip__pin_item">Element anheften</string>
<string name="clip__delete_item">Löschen</string>
<string name="clip__paste_item">Einfügen</string>
<string name="clip__back_to_text_input">Zurück zur Texteingabe</string>
<string name="clip__cant_paste">Diese App erlaubt kein Einfügen aus der Zwischenablage.</string>
</resources>

View File

@@ -153,7 +153,7 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Πολλαπλασιαστής μεγέθους γραμματοσειράς (πορτραίτο)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">Λειτουργία ενός χεριού</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Λειτουργία ενός χεριού</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Ανενεργό</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Λειτουργία για δεξιόχειρες</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Λειτουργία για αριστερόχειρες</string>
@@ -302,4 +302,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Πατήστε για προβολή λεπτομερειών σφάλματος</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Φαίνεται πως το FlorisBoard σταματά να λειτουργεί επανειλημμένα…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Χρήση εναλλακτικά του προηγούμενου πληκτρολογίου για να σταματήσει ο αδιάκοπος κύκλος κρασαρισμάτων. Πατήστε για να δείτε λεπτομέρειες του σφάλματος</string>
<!-- clipboard strings -->
</resources>

View File

@@ -163,4 +163,5 @@
<!-- Crash Dialog strings -->
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">Kopii al tondejo</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Fermi</string>
<!-- clipboard strings -->
</resources>

View File

@@ -78,21 +78,25 @@
<string name="pref__theme__any_theme__label" comment="Label of the theme selector preference">Tema seleccionado</string>
<string name="pref__theme__any_theme_adapt_to_app__label" comment="Label of the theme adapt to app preference">Adaptar colores a la aplicación</string>
<string name="pref__theme__any_theme_adapt_to_app__summary" comment="Summary of the theme adapt to app preference">Los colores del tema se adaptan a los de la aplicación actual, si la aplicación de destino lo admite.</string>
<string name="pref__theme__source_assets" comment="Label for the theme source field">Activos de la aplicación FlorisBoard</string>
<string name="pref__theme__source_internal" comment="Label for the theme source field">Almacenamiento interno</string>
<string name="pref__theme__source_external" comment="Label for the theme source field">Almacenamiento externo</string>
<string name="settings__theme_manager__title_day" comment="Title of the theme manager activity for day theme">Administrador de tema (claro)</string>
<string name="settings__theme_manager__title_night" comment="Title of the theme manager activity for night theme">Administrador de tema (Oscuro)</string>
<string name="settings__theme_manager__create_empty" comment="Label of the Create empty FAB action">Crear un tema nuevo</string>
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Crear de tema seleccionado</string>
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Crear a partir del tema seleccionado</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Personalizado (basado en %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Nuevo tema</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">¡Tema importado correctamente!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">¡Tema exportado correctamente!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Editar tema</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nombre</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Tipo</string>
<string name="settings__theme_editor__add_group_dialog_title" comment="Title of the add group dialog in the theme editor">Agregar grupo</string>
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Editar grupo</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Agregar atributo</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Editar Atributo</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Editar atributo</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Editar nombre del tema</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Referencia</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Grupo</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atributo</string>
@@ -111,7 +115,7 @@
<string name="settings__theme_editor__error_attr_name" comment="Error text for an invalid attribute name">Por favor, ingresa un nombre que contenga solo las letras a-z y/o A-Z.</string>
<string name="settings__theme_editor__error_attr_name_empty" comment="Error text for an empty attribute name">Por favor, introduzca un nombre al atributo.</string>
<string name="settings__theme_editor__error_attr_name_already_exists" comment="Error text for a duplicate attribute name">Este nombre de atributo ya existe en este grupo. Por favor, escribe otro.</string>
<string name="settings__theme__group_window" comment="Theme group label">Ventana y sistema</string>
<string name="settings__theme__group_window" comment="Theme group label">Ventana &amp; sistema</string>
<string name="settings__theme__group_keyboard" comment="Theme group label">Teclado</string>
<string name="settings__theme__group_key" comment="Theme group label">Tecla</string>
<string name="settings__theme__group_key_specific" comment="Theme group label (%s is specific modifier)">Tecla (%s)</string>
@@ -120,7 +124,9 @@
<string name="settings__theme__group_popup" comment="Theme group label">Emergente</string>
<string name="settings__theme__group_privateMode" comment="Theme group label">Modo privado</string>
<string name="settings__theme__group_smartbar" comment="Theme group label">Barra inteligente</string>
<string name="settings__theme__group_smartbarButton" comment="Theme group label">ton de barra inteligente</string>
<string name="settings__theme__group_smartbarButton" comment="Theme group label">Botón de barra inteligente</string>
<string name="settings__theme__group_extractEditLayout" comment="Theme group label">Distribución de pantalla completa horizontal</string>
<string name="settings__theme__group_extractActionButton" comment="Theme group label">Botón de acción de pantalla completa horizontal</string>
<string name="settings__theme__group_custom" comment="Theme group label (%s is custom group name)">Grupo personalizado (%s)</string>
<string name="settings__theme__attr_background" comment="Theme attribute label">Color de fondo</string>
<string name="settings__theme__attr_backgroundActive" comment="Theme attribute label">Color de fondo (activo)</string>
@@ -140,13 +146,13 @@
<string name="settings__keyboard__title" comment="Title of Keyboard preferences fragment">Preferencias de teclado</string>
<string name="pref__keyboard__group_keys__label" comment="Preference group title">Teclas</string>
<string name="pref__keyboard__number_row__label" comment="Preference title">Fila de números</string>
<string name="pref__keyboard__number_row__summary" comment="Preference summary">Mostrar fila de números sobre la distribución de los caracteres</string>
<string name="pref__keyboard__number_row__summary" comment="Preference summary">Mostrar fila de números en la parte superior del teclado</string>
<string name="pref__keyboard__hinted_number_row_mode__label" comment="Preference title">Fila de números sugeridos</string>
<string name="pref__keyboard__hinted_symbols_mode__label" comment="Preference title">Símbolos sugeridos</string>
<string name="pref__keyboard__hint_mode__disabled" comment="Preference value">Deshabilitado</string>
<string name="pref__keyboard__hint_mode__enabled_hint_priority" comment="Preference value">Habilitado (Prioridad en la sugerencia)</string>
<string name="pref__keyboard__hint_mode__enabled_accent_priority" comment="Preference value">Habilitado (Prioridad en el acento)</string>
<string name="pref__keyboard__hint_mode__enabled_smart_priority" comment="Preference value">Habilitado (Priorización inteligente)</string>
<string name="pref__keyboard__hint_mode__enabled_smart_priority" comment="Preference value">Habilitado (Priorizar de forma inteligente)</string>
<string name="pref__keyboard__utility_key_enabled__label" comment="Preference title">Mostrar teclas de utilidad</string>
<string name="pref__keyboard__utility_key_enabled__summary" comment="Preference summary">Muestra una tecla de utilidad configurable junto a la barra espaciadora</string>
<string name="pref__keyboard__utility_key_action__label" comment="Preference title">Acción de tecla de utilidad</string>
@@ -157,10 +163,12 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplicador del tamaño de la fuente (vertical)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplicador del tamaño de la fuente (horizontal)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Distribución</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Modo a una mano</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Modo a una mano</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Apagado</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Modo para diestros</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Modo para zurdos</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Ancho del teclado en modo de una mano</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Entrada a pantalla completa horizontal</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">No mostrar nunca</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Mostrar siempre</string>
<string name="pref__keyboard__landscape_input_ui_mode__dynamically_show" comment="Preference value">Mostrar dinámicamente</string>
@@ -174,14 +182,17 @@
<string name="pref__keyboard__height_factor__extra_tall" comment="Preference value">Muy alto</string>
<string name="pref__keyboard__height_factor__custom" comment="Preference value">Personalizado</string>
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Valor de altura del teclado personalizada</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Desplazamiento inferior</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Pulsación de tecla</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Sonido al pulsar la tecla</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Volumen del sonido al pulsar la tecla</string>
<string name="pref__keyboard__vibration_enabled__label" comment="Preference title">Vibración al pulsar la tecla</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">Intensidad de la vibración al pulsar la tecla</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Desplazamiento inferior (vertical)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Desplazamiento inferior (horizontal)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Espacio entre teclas (vertical)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">Espacio entre teclas (horizontal)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Presionar tecla</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Sonido al presionar una tecla</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Volumen del sonido al presionar una tecla</string>
<string name="pref__keyboard__vibration_enabled__label" comment="Preference title">Vibración al presionar una tecla</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">Intensidad de la vibración al presionar una tecla</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Visibilidad de las teclas emergentes</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Muestra la tecla emergente al ser pulsada</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Ampliar al pulsar una tecla</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Retardo de la pulsación larga</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Experiencia de escritura</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Habilitar barra inteligente</string>
@@ -192,12 +203,12 @@
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Poner en mayúsculas las palabras según el contexto de entrada actual</string>
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">Recordar el estado de bloqueo de las mayúsculas</string>
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">El bloqueo de las mayúsculas se mantendrá cuando se pase a otro campo de texto</string>
<string name="pref__correction__double_space_period__label" comment="Preference title">Periodo de espacio doble</string>
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Pulsar dos veces en la barra espaciadora inserta un periodo seguido de un espacio</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">Gestos y escritura deslizante</string>
<string name="pref__correction__double_space_period__label" comment="Preference title">Punto y doble espacio</string>
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Al presionar dos veces en la barra espaciadora se inserta un punto seguido de un espacio</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">Gestos &amp; escritura deslizante</string>
<string name="pref__glide__title" comment="Preference group title">Escritura deslizante</string>
<string name="pref__glide__enabled__label" comment="Preference title">[NYI] Habilitar escritura deslizante</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Escriba una palabra deslizando su dedo a través de sus letras</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Escriba una palabra deslizando su dedo a través de las letras</string>
<string name="pref__glide__show_trail__label" comment="Preference title">[NYI] Mostrar recorrido del deslizamiento</string>
<string name="pref__glide__show_trail__summary" comment="Preference summary">Desaparecerá después de cada palabra</string>
<string name="pref__gestures__general_title" comment="Preference group title">Gestos generales</string>
@@ -211,42 +222,44 @@
<string name="pref__gestures__swipe_action__insert_space" comment="Preference value for swipe action">Insertar espacio</string>
<string name="pref__gestures__swipe_action__move_cursor_up" comment="Preference value for swipe action">Mover cursor hacia arriba</string>
<string name="pref__gestures__swipe_action__move_cursor_down" comment="Preference value for swipe action">Mover cursor hacia abajo</string>
<string name="pref__gestures__swipe_action__move_cursor_left" comment="Preference value for swipe action">Mover cursor hacia la izquierda</string>
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Mover cursor hacia la derecha</string>
<string name="pref__gestures__swipe_action__move_cursor_left" comment="Preference value for swipe action">Mover cursor a la izquierda</string>
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Mover cursor a la derecha</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Mover cursor al inicio de la línea</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Mover cursor al final de la línea</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Mover cursor al inicio de la página</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Mover cursor al final de la página</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Mayúsculas</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Mostrar selector de método de entrada</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Seleccionar método de entrada</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Cambiar al teclado anterior</string>
<string name="pref__gestures__swipe_action__switch_to_prev_subtype" comment="Preference value for swipe action">Cambiar al subtipo anterior</string>
<string name="pref__gestures__swipe_action__switch_to_next_subtype" comment="Preference value for swipe action">Cambiar al subtipo siguiente</string>
<string name="pref__gestures__swipe_up__label" comment="Preference title">Deslizar arriba</string>
<string name="pref__gestures__swipe_down__label" comment="Preference title">Deslizar abajo</string>
<string name="pref__gestures__swipe_up__label" comment="Preference title">Deslizar hacia arriba</string>
<string name="pref__gestures__swipe_down__label" comment="Preference title">Deslizar hacia abajo</string>
<string name="pref__gestures__swipe_left__label" comment="Preference title">Deslizar a la izquierda</string>
<string name="pref__gestures__swipe_right__label" comment="Preference title">Deslizar a la derecha</string>
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Deslizar arriba en la barra espaciadora</string>
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Deslizar a la izquierda en la barra espaciadora</string>
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Deslizar a la derecha en la barra espaciadora</string>
<string name="pref__gestures__space_bar_long_press__label" comment="Preference title">Pulsación larga de la barra espaciadora</string>
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Eliminar deslizamiento de la tecla a la izquierda</string>
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Umbral de la velocidad de deslizamiento</string>
<string name="pref__gestures__space_bar_long_press__label" comment="Preference title">Presionar por mucho tiempo la barra espaciadora</string>
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Deslizar a la izquierda desde la tecla de borrar</string>
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Velocidad del deslizamiento</string>
<string name="pref__gestures__swipe_velocity_threshold__very_slow" comment="Preference value for swipe velocity threshold">Muy lento</string>
<string name="pref__gestures__swipe_velocity_threshold__slow" comment="Preference value for swipe velocity threshold">Lento</string>
<string name="pref__gestures__swipe_velocity_threshold__normal" comment="Preference value for swipe velocity threshold">Normal</string>
<string name="pref__gestures__swipe_velocity_threshold__fast" comment="Preference value for swipe velocity threshold">Rápido</string>
<string name="pref__gestures__swipe_velocity_threshold__very_fast" comment="Preference value for swipe velocity threshold">Muy rápido</string>
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Umbral de distancia del deslizamiento</string>
<string name="pref__gestures__swipe_distance_threshold__very_short" comment="Preference value for swipe distance threshold">Muy corto</string>
<string name="pref__gestures__swipe_distance_threshold__short" comment="Preference value for swipe distance threshold">Corto</string>
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Distancia del deslizamiento</string>
<string name="pref__gestures__swipe_distance_threshold__very_short" comment="Preference value for swipe distance threshold">Muy corta</string>
<string name="pref__gestures__swipe_distance_threshold__short" comment="Preference value for swipe distance threshold">Corta</string>
<string name="pref__gestures__swipe_distance_threshold__normal" comment="Preference value for swipe distance threshold">Normal</string>
<string name="pref__gestures__swipe_distance_threshold__long" comment="Preference value for swipe distance threshold">Largo</string>
<string name="pref__gestures__swipe_distance_threshold__very_long" comment="Preference value for swipe distance threshold">Muy largo</string>
<string name="pref__gestures__swipe_distance_threshold__long" comment="Preference value for swipe distance threshold">Larga</string>
<string name="pref__gestures__swipe_distance_threshold__very_long" comment="Preference value for swipe distance threshold">Muy larga</string>
<string name="settings__advanced__title" comment="Title of Advanced settings activity">Avanzado</string>
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Tema de los ajustes</string>
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Ajustes del tema</string>
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Claro</string>
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Oscuro</string>
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Mostrar icono de la aplicación en el launcher</string>
<string name="pref__advanced__force_private_mode__label" comment="Label of Force private mode preference in Advanced">Forzar el modo privado</string>
<string name="pref__advanced__force_private_mode__label" comment="Label of Force private mode preference in Advanced">Forzar modo privado</string>
<string name="pref__advanced__force_private_mode__summary" comment="Summary of Force private mode preference in Advanced">Desactivará cualquier característica que tenga que trabajar temporalmente con sus datos de entrada</string>
<!-- About UI strings -->
<string name="about__title" comment="Title of About activity">Acerca de</string>
@@ -275,14 +288,16 @@
<string name="assets__action__no">No</string>
<string name="assets__action__save">Guardar</string>
<string name="assets__action__yes">Si</string>
<string name="assets__error__details">Detalles</string>
<string name="assets__error__invalid">Inválido</string>
<string name="assets__error__snackbar_message">Algo salió mal</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Configuración</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Anterior</string>
<string name="setup__cancel_button" comment="Label of Cancel button in Setup">Cancelar</string>
<string name="setup__next_button" comment="Label of Next button in Setup (try to find a short translation due to limited space in UI)">Siguiente</string>
<string name="setup__finish_button" comment="Label of Finish button in Setup">Terminar</string>
<string name="setup__ok_button" comment="Label of OK button in Setup">VALE</string>
<string name="setup__ok_button" comment="Label of OK button in Setup">OK</string>
<string name="setup__welcome__title" comment="Title of Welcome fragment in Setup">¡Bienvenido/a!</string>
<string name="setup__welcome__intro" comment="Paragraph in Welcome fragment in Setup">¡Gracias por probar FlorisBoard! Antes de que puedas empezar a usarlo, tenemos que hacer lo habitual y habilitarlo en la configuración del sistema, configurar tu idioma/distribución preferida, etc… Pero no te preocupes, ¡el asistente de configuración te guiará a través de esto!</string>
<string name="setup__welcome__privacy" comment="Paragraph in Welcome fragment in Setup">FlorisBoard respeta totalmente su privacidad y no recoge ningún dato de los usuarios. Para más información vea aquí:</string>
@@ -290,9 +305,9 @@
<string name="setup__welcome__contribute" comment="Paragraph in Welcome fragment in Setup">Una última cosa antes de empezar la configuración, si encuentras algún error, fallo o problema con FlorisBoard o tienes una petición de características, dirígete al repositorio GitHub enlazado abajo e informa sobre la incidencia. ¡Esto ayuda a mejorar la experiencia de todos los usuarios!</string>
<string name="setup__welcome__outro" comment="Paragraph in Welcome fragment in Setup">Para iniciar la configuración, haga clic en <i>SIGUIENTE</i>.</string>
<string name="setup__enable_ime__title" comment="Title of Enable IME fragment in Setup">Habilitar FlorisBoard</string>
<string name="setup__enable_ime__text_before_enabled" comment="Description of state in Enable IME fragment before user enabled">Android requiere que cada teclado personalizado sea habilitado manualmente antes de que puedas usarlo. Haga clic en el botón de abajo para ir a la configuración de <i>Idiomas e introducción de texto</i>, luego asegúrese de marcar \'<i>FlorisBoard</i>\'.</string>
<string name="setup__enable_ime__text_after_enabled" comment="Description of state in Enable IME fragment after user enabled">FlorisBoard ha sido habilitado con éxito. ¡Para continuar haga clic en <i>SIGUIENTE</i>!</string>
<string name="setup__enable_ime__text_button_language_and_input" comment="Label of language and input button in Enable IME fragment">Abrir Idioma e introducción de texto</string>
<string name="setup__enable_ime__text_before_enabled" comment="Description of state in Enable IME fragment before user enabled">Android requiere que cada teclado personalizado sea habilitado manualmente antes de que puedas usarlo. Haz clic en el botón de abajo para ir a la configuración de <i>Idiomas &amp; introducción de texto</i>, luego asegurate de marcar \'<i>FlorisBoard</i>\'.</string>
<string name="setup__enable_ime__text_after_enabled" comment="Description of state in Enable IME fragment after user enabled">FlorisBoard ha sido habilitado con éxito. ¡Para continuar haz clic en <i>SIGUIENTE</i>!</string>
<string name="setup__enable_ime__text_button_language_and_input" comment="Label of language and input button in Enable IME fragment">Abrir Idioma &amp; introducción de texto</string>
<string name="setup__make_default__title" comment="Title of Make IME default fragment in Setup">Hacer a FlorisBoard el teclado por defecto</string>
<string name="setup__make_default__text_before_switch" comment="Description of state in Make IME default fragment before user switched">FlorisBoard está ahora habilitado en tu sistema. Para usarlo activamente, ¡cambia a FlorisBoard seleccionándolo en el diálogo del selector de entrada!</string>
<string name="setup__make_default__text_after_switch" comment="Description of state in Make IME default fragment after user switched">¡Cambió con éxito el teclado por defecto a FlorisBoard!</string>
@@ -300,13 +315,23 @@
<string name="setup__finish__title" comment="Title of Setup finished fragment in Setup">¡Configuración terminada!</string>
<!-- Crash Dialog strings -->
<string name="crash_dialog__title" comment="Title of crash dialog">Informe de errores de FlorisBoard</string>
<string name="crash_dialog__description" comment="Description of crash dialog">Sentimos las molestias, pero FlorisBoard se ha cerrado debido a un error inesperado.\n\nSi desea informar de este error, haga clic en \"Copiar al portapapeles\", y luego en el botón \"Abrir informe de errores\". Rellene el informe de errores y pegue el registro. Esto ayuda a que FlorisBoard sea mejor y más estable para todos. ¡Gracias a todos!</string>
<string name="crash_dialog__description" comment="Description of crash dialog">Sentimos las molestias, pero FlorisBoard se ha cerrado debido a un error inesperado.\n\nSi desea informar de este error, haga clic en \"Copiar al portapapeles\", y luego en el botón \"Abrir informe de errores\". Rellene el informe de errores y pegue el registro. Esto ayuda a que FlorisBoard sea mejor y más estable para todos. ¡Gracias!</string>
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">Copiar al portapapeles</string>
<string name="crash_dialog__open_bug_report_form" comment="Label of Open bug report button in crash dialog">Abrir formulario de reporte de errores (github.com)</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Cerrar</string>
<string name="crash_notification_channel__title" comment="Title of crash notification channel">Informes de errores de FlorisBoard</string>
<string name="crash_once_notification__title" comment="Title of the notification for a single crash">FlorisBoard ha dejado de funcionar…</string>
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Pulsa para ver los detalles del error</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard parece dejar de funcionar repetidamente…</string>
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Toca para ver detalles</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Parece que FlorisBoard ha dejado de funcionar repetidamente…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Volviendo al teclado anterior para detener el bucle de cierre infinito. Toque para ver los detalles del error</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Cambiar al historial del portapapeles</string>
<string name="clip__context_header">Historial del portapapeles</string>
<string name="clip__clear_history">Borrar historial</string>
<string name="clip__unpin_item">Desanclar</string>
<string name="clip__pin_item">Anclar</string>
<string name="clip__delete_item">Borrar</string>
<string name="clip__paste_item">Pegar</string>
<string name="clip__back_to_text_input">Volver a la entrada de texto</string>
<string name="clip__cant_paste">Esta aplicación no permite pegar el contenido.</string>
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">ساختن از طرح‌زمینه انتخاب شده</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">سفارشی (بر اساس %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">طرح‌زمینه جدید</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">تم با موفقیت افزوده شد!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">تم با موفقیت استخراج شد!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">ویرایش طرح زمینه</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">نام</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">نوع</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">ویرایش گروه</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">افزودن ویژگی</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">ویرایش ویژگی</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">ویرایش نام طرح زمینه</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">مرجع</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">گروه</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">ویژگی</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">اندازه فونت چند برابری(عمودی)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">حالت تک دستی</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">حالت تک دستی</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">خاموش</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">حالت دست راستی</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">حالت دست چپی</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__landscape_input_ui_mode__never_show" comment="Preference value">هرگز نشان نده</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">همیشه نشان بده</string>
@@ -190,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">نمایش پاپ‌آپ</string>
<string name="pref__keyboard__popup_visible__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>
<string name="settings__typing__title" comment="Title of Typing experience fragment">تجربه در تایپ کردن</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">فعال سازی نوار هوشمند</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">بالای صفحه‌کلید نمایش داده خواهند شد</string>
@@ -208,7 +214,7 @@
<string name="pref__glide__show_trail__label" comment="Preference title">[NYI] نشان دادن دنباله سر خوردن</string>
<string name="pref__glide__show_trail__summary" comment="Preference summary">بعد از هر کلمه ناپدید خواهد شد</string>
<string name="pref__gestures__general_title" comment="Preference group title">اشارات کلی</string>
<string name="pref__gestures__space_bar_title" comment="Preference group title">دکمه space اشارات</string>
<string name="pref__gestures__space_bar_title" comment="Preference group title">حرکات نوار فاصله</string>
<string name="pref__gestures__other_title" comment="Preference group title">دیگر اشارات/ آشارات آستانه</string>
<string name="pref__gestures__swipe_action__no_action" comment="Preference value for swipe action">بدون عمل</string>
<string name="pref__gestures__swipe_action__delete_characters_precisely" comment="Preference value for swipe action">حذف کردن دقیق حروف</string>
@@ -284,7 +290,9 @@
<string name="assets__action__no">خیر</string>
<string name="assets__action__save">ذخیره</string>
<string name="assets__action__yes">بله</string>
<string name="assets__error__details">جزئیات</string>
<string name="assets__error__invalid">نامعتبر</string>
<string name="assets__error__snackbar_message">یک چیزی اشتباه پیش رفت</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">راه‌اندازی</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">قبلی</string>
@@ -310,7 +318,7 @@
<!-- Crash Dialog strings -->
<string name="crash_dialog__title" comment="Title of crash dialog">گزارش خطای فلوریس بورد</string>
<string name="crash_dialog__description" comment="Description of crash dialog">با عرض پوزش برای این مشکل ، اما فلوریس بورد به دلیلی غیرمنتظره ای متوفق شده است.\n\n اگر می خواهید این خطا را گزارش کنید ، روی \"کپی در کلیپ بورد\" کلیک کنید ، سپس بر روی دکمه \"باز کردن گزارش اشکال\" کلیک کنید. گزارش اشکال را پر کرده و گزارش را وارد کنید. این امر به بهتر و پایدارتر شدن فلوریس بورد برای همه کمک می کند. متشکرم!</string>
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">در کلیپ بورد کپی شد</string>
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">کپی در حافطه موقت</string>
<string name="crash_dialog__open_bug_report_form" comment="Label of Open bug report button in crash dialog">باز کردن گزارش خطا توسط (github.com)</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">بستن</string>
<string name="crash_notification_channel__title" comment="Title of crash notification channel">گزارش های خطای فلوریس بورد</string>
@@ -318,4 +326,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">برای دیدن جزئیات خطا ضربه بزنید</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">به نظر می رسد فلوریس بورد کار خود را مکرر متوقف می کند…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">در خال بازگشت به کیبورد قبلی برای جلو گیری از بروز خطای دوباره. برای مشاهده جزئیات خطا ، ضربه بزنید</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">تغییر به تاریخچه کلیپ بورد</string>
<string name="clip__context_header">تاریخچه کلیپ بورد</string>
<string name="clip__clear_history">پاک‌سازی تاریخچه</string>
<string name="clip__unpin_item">برداشتن نشانه</string>
<string name="clip__pin_item">نشانه گذاری</string>
<string name="clip__delete_item">حذف</string>
<string name="clip__paste_item">چسباندن</string>
<string name="clip__back_to_text_input">بازگشت به ورودی متن</string>
<string name="clip__cant_paste">این برنامه اجازه چسباندن این محتوا را نمی دهد.</string>
</resources>

View File

@@ -70,7 +70,7 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Fonttikoon kerroin (pystysuunnassa)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Fonttikoon kerroin (vaakasuunnassa)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Ulkoasu</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Yksikätinen tila</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Yksikätinen tila</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Pois päältä</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Oikean käden tila</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Vasemman käden tila</string>
@@ -184,4 +184,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Napauta nähdäksesi virheen tiedot</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard vaikuttaa lopettavan toimintansa toistuvasti…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Vaihdetaan edelliseen näppäimistöön, jotta kaatumiskierre loppuu. Napauta nähdäksesi virheen tiedot</string>
<!-- clipboard strings -->
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Créer depuis le thème sélectionné</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Personnalisé (basé sur %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Nouveau thème</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Thème importé avec succès !</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Thème exporté avec succès !</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Modifier le thème</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nom</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Type</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Modifier le groupe</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Ajouter un attribut</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Modifier l\'attribut</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Modifier le nom du thème</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Référence</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Groupe</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Attribut</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplicateur de la taille de la police (portrait)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplicateur de la taille de la police (paysage)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Disposition</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Mode à une main</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Mode à une main</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Désactivé</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Mode droitier</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Mode gaucher</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Largeur du clavier en mode une main</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Insertion horizontale en plein écran</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Ne jamais afficher</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Toujours afficher</string>
@@ -180,6 +184,8 @@
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Valeur personnalisée de la hauteur du clavier</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Écart en bas (portrait)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Écart en bas (paysage)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Espacement des touches (vertical)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">Espacement des touches (horizontal)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Touche pressée</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Tonalité des touches</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Volume sonore des touches</string>
@@ -220,6 +226,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Déplacer le curseur vers la droite</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Déplacer le curseur au début de la ligne</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Déplacer le curseur à la fin de la ligne</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Déplacer le curseur au début de la page</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Déplacer le curseur à la fin de la page</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Maj</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Afficher le sélecteur de mode de saisie</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Passer à la disposition précédente</string>
@@ -280,7 +288,9 @@
<string name="assets__action__no">Non</string>
<string name="assets__action__save">Sauvegarder</string>
<string name="assets__action__yes">Oui</string>
<string name="assets__error__details">Détails</string>
<string name="assets__error__invalid">Invalide</string>
<string name="assets__error__snackbar_message">Un problème est survenu</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Configuration</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Préc</string>
@@ -314,4 +324,11 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Appuyez sur pour afficher les détails de l\'erreur</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard semble cesser de fonctionner de façon répétitive…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Retour au clavier précédent pour arrêter la boucle de plantage infinie. Appuyez pour afficher les détails de l\'erreur</string>
<!-- clipboard strings -->
<string name="clip__context_header">Historique du presse-papiers</string>
<string name="clip__clear_history">Effacer l\'historique</string>
<string name="clip__delete_item">Effacer</string>
<string name="clip__paste_item">Coller</string>
<string name="clip__back_to_text_input">Retour à la saisie de texte</string>
<string name="clip__cant_paste">Cette app ne permet pas de coller ce contenu.</string>
</resources>

View File

@@ -13,4 +13,5 @@
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -2,7 +2,7 @@
<resources>
<string name="app_name">FlorisBoard</string>
<string name="key__phone_pause" comment="Label for the Pause key in the telephone keyboard layout">Szünet</string>
<string name="key__phone_wait" comment="Label for the Wait key in the telephone keyboard layout">Várakozás</string>
<string name="key__phone_wait" comment="Label for the Wait key in the telephone keyboard layout">Kérem várjon</string>
<string name="key_popup__threedots_alt" comment="Content description for the three-dots icon in a key popup">Hárompontos ikon. Ha látható, azt jelzi, hogy több betű használható, ha hosszabb ideig megnyomja.</string>
<!-- One-handed strings -->
<string name="one_handed__close_btn_content_description" comment="Content description for the one-handed close button">Egykezes mód bezárása.</string>
@@ -18,7 +18,7 @@
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emotikonok</string>
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
<!-- Emoji strings -->
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Mosolyok &amp; érzelmek</string>
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Mosolyok és érzelmek</string>
<string name="emoji__category__people_body" comment="Emoji category name">Emberek és test</string>
<string name="emoji__category__animals_nature" comment="Emoji category name">Állatok és természet</string>
<string name="emoji__category__food_drink" comment="Emoji category name">Étel és ital</string>
@@ -42,7 +42,7 @@
<string name="settings__menu" comment="Hint of top-right three-dot icon in Settings">További beállítások</string>
<string name="settings__menu_help" comment="Three-dot menu entry for Help and Feedback web link">Segítség és visszajelzés</string>
<string name="settings__help" comment="General label for help buttons in Settings">Súgó</string>
<string name="settings__navigation__home" comment="Long-press hint of bottom nav item Home in Settings">Kezdés</string>
<string name="settings__navigation__home" comment="Long-press hint of bottom nav item Home in Settings">Kezdőlap</string>
<string name="settings__navigation__keyboard" comment="Long-press hint of bottom nav item Keyboard in Settings">Billentyűzet</string>
<string name="settings__navigation__typing" comment="Long-press hint of bottom nav item Typing in Settings">Gépelés</string>
<string name="settings__navigation__theme" comment="Long-press hint of bottom nav item Theme in Settings">Téma</string>
@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Létrehozás a kiválasztott témából</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Egyéni (ezen alapul: %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Új téma</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Téma sikeresen importálva!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Téma sikeresen exportálva!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Téma szerkesztése</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Név</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Típus</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Csoport szerkesztése</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Tulajdonság hozzáadása</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Tulajdonság szerkesztése</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Téma nevének szerkesztése</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Hivatkozás</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Csoport</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Tulajdonság</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Betűméret szorzó (álló)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Betűméret szorzó (fekvő)</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 value">Egykezes mód</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Egykezes mód</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Ki</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Jobbkezes mód</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Balkezes 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>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Teljes képernyős fekvő elrendezés bemenet</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Soha ne jelenjen meg</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Mindig jelenjen meg</string>
@@ -180,14 +184,18 @@
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Egyéni billentyűzetmagasság értéke</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Alsó eltolás (álló)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Alsó eltolás (fekvő)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Gombtávolság (vízszintes)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">Gombtávolság (függőleges)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Gombnyomás</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Hang gombnyomáskor</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Gombnyomás hangereje</string>
<string name="pref__keyboard__vibration_enabled__label" comment="Preference title">Rezgés gombnyomáskor</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">Rezgés erőssége gombnyomáskor</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Felugró megjelenítése</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Felugró megjelenítése gombnyomáskor</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Nagyobb gomb megjelenítése</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Nagyobb gomb megjelenítése gombnyomáskor</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Hosszú gombnyomás késleltetése</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Szóköz automatikusan visszavált a karakterelrendezésre</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">A szóköz lenyomáskor automatikusan visszavált a karakterekre, amikor a szimbólumok vagy a számok jelennek meg</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Gépelési élmény</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Okossáv engedélyezése</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">A billentyűzet tetején fog megjelenni</string>
@@ -199,7 +207,7 @@
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Caps lock marad, ha mozog egy másik szövegmezőbe</string>
<string name="pref__correction__double_space_period__label" comment="Preference title">Dupla szóköz: pont</string>
<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__gestures__title" comment="Title of Gestures fragment">Gesztusok &amp; csúsztatott gépelés</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">Gesztusok és csúsztatott gépelés</string>
<string name="pref__glide__title" comment="Preference group title">Csúsztatott gépelés</string>
<string name="pref__glide__enabled__label" comment="Preference title">[NYI] Csúsztatott gépelés engedélyezése</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Írjon be egy szót úgy, hogy ujját a betűin keresztülcsúsztatja</string>
@@ -220,6 +228,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Kurzor mozgatása jobbra</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Kurzor sor elejére helyezése</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Kurzor sor végére helyezése</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Kurzor mozgatása a lap elejére</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Kurzor mozgatása a lap végére</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Shift</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Bevitelválasztó megnyitása</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Váltás az előző billentyűzetre</string>
@@ -276,7 +286,9 @@
<string name="assets__action__no">Nem</string>
<string name="assets__action__save">Mentés</string>
<string name="assets__action__yes">Igen</string>
<string name="assets__error__details">Részletek</string>
<string name="assets__error__invalid">Érvénytelen</string>
<string name="assets__error__snackbar_message">Valami rosszul sült el</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Beállítás</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Előző</string>
@@ -310,4 +322,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Érintse meg a hiba részleteinek megtekintéséhez</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Úgy tűnik, hogy a FlorisBoard többször leállt…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Visszalépés az előző billentyűzetre, a végtelen összeomlás megakadályozásához. Érintse meg a hiba részleteinek megtekintéséhez</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Váltás a vágólapelőzményekre</string>
<string name="clip__context_header">Vágólap előzmények</string>
<string name="clip__clear_history">Előzmények törlése</string>
<string name="clip__unpin_item">Elem levétele</string>
<string name="clip__pin_item">Elem kitűzése</string>
<string name="clip__delete_item">Törlés</string>
<string name="clip__paste_item">Beillesztés</string>
<string name="clip__back_to_text_input">Vissza a szöveges bevitelre</string>
<string name="clip__cant_paste">Ez az alkalmazás nem engedélyezi beilleszteni ezt a tartalmat.</string>
</resources>

View File

@@ -29,7 +29,7 @@
<string name="emoji__category__flags" comment="Emoji category name">Bandiere</string>
<!-- Smartbar strings -->
<string name="smartbar__quick_action_toggle__alt" comment="Content description for the quick action toggle button in Smartbar">Attiva/disattiva azione rapida. Se premuto, alterna i suggerimenti di parole ed i pulsanti di azione rapida.</string>
<string name="smartbar__quick_action__exit_editing" comment="Content-description for the exit editing layout button in Smartbar">Pannello di modifica del testo.</string>
<string name="smartbar__quick_action__exit_editing" comment="Content-description for the exit editing layout button in Smartbar">Esci dal pannello di modifica del testo.</string>
<string name="smartbar__quick_action__one_handed_mode" comment="Content-description for the one-handed quick action in Smartbar">Attiva/disattiva la modalità con una mano.</string>
<string name="smartbar__quick_action__open_settings" comment="Content-description for the settings quick action in Smartbar">Apri Impostazioni.</string>
<string name="smartbar__quick_action__switch_to_editing_context" comment="Content-description for the editing quick action in Smartbar">Vai a pannello di modifica del testo.</string>
@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Crea dal tema selezionato</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Personalizzato (basato su %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Nuovo tema</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Tema importato correttamente!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Tema esportato correttamente!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Modifica tema</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nome</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Tipo</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Modifica gruppo</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Aggiungi attributo</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Modifica attributo</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Modifica il nome del tema</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Referenze</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Gruppo</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Attributo</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Moltiplicatore della dimensione del testo (ritratto)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Moltiplicatore della dimensione del testo (panorama)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Layout</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Modalità ad una mano</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Modalità ad una mano</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Off</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Modalità destrimano</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Modalità mancino</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Larghezza della tastiera in modalità a una mano</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Inserimento a schermo intero orizzontale</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Non mostrare</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Mostra sempre</string>
@@ -180,6 +184,8 @@
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Valore Altezza tastiera personalizzata</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Distanza inferiore (verticale)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Distanza inferiore (orizzontale)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Spazio fra i pulsanti (verticale)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">Spazio fra i pulsanti (orizzontale)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">Pressione tasti</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Suono pressione tasti</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Volume del suono alla pressione dei tasti</string>
@@ -188,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Visibilità Popup</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Mostra popup quando si preme un tasto</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Ritardo lunga pressione tasti</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">La barra spaziatrice riporta alla digitazione a caratteri</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Premendo la barra spaziatrice si ritorna automaticamente ai caratteri quando si è nei simboli o numeri</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Esperienza di digitazione</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Abilità Smartbar</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Verrà mostrato in cima alla tastiera</string>
@@ -220,6 +228,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Muovi cursore a destra</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Spazia il cursore all\'inizio della linea</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Spazia il cursore alla fine della linea</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Sposta il cursore all\'inizio della pagina</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Sposta il cursore alla fine della pagina</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Shift</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Mostra il selettore del metodo di digitazione</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Passa alla tastiera precedente</string>
@@ -280,7 +290,9 @@
<string name="assets__action__no">No</string>
<string name="assets__action__save">Salva</string>
<string name="assets__action__yes"></string>
<string name="assets__error__details">Dettagli</string>
<string name="assets__error__invalid">Invalido</string>
<string name="assets__error__snackbar_message">Qualcosa è andato storto</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Configurazione</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Precedente</string>
@@ -314,4 +326,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Tocca per visualizzare i dettagli dell\'errore</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard sembra aver ripetutamente smesso di funzionare…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Ripiega alla tastiera precedente per porre fine ai crash ripetuti. Tocca per visualizzare i dettagli dell\'errore</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Passa alla cronologia appunti</string>
<string name="clip__context_header">Cronologia appunti</string>
<string name="clip__clear_history">Cancella la cronologia</string>
<string name="clip__unpin_item">Sblocca oggetto</string>
<string name="clip__pin_item">Blocca oggetto</string>
<string name="clip__delete_item">Elimina</string>
<string name="clip__paste_item">Incolla</string>
<string name="clip__back_to_text_input">Torna all\'immissione di testo</string>
<string name="clip__cant_paste">Questa app non permette di incollare questo contenuto.</string>
</resources>

View File

@@ -157,7 +157,7 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">מכפלת גודל גופן (אנכי)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">מצב יד אחת</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">מצב יד אחת</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">כבה</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">מצב ליד ימין</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">מצב לשמאליים</string>
@@ -307,4 +307,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">לחץ להצגת פרטי השגיאה</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">נראה שFlorisBoard מפסיק לעבוד שוב שוב…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">המקדלת הקומדת הוחזרה כדי למנוע לולאת קריסה אינסופית. לחץ כדי לראות את פרטי השגיאה</string>
<!-- clipboard strings -->
</resources>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">FlorisBoard</string>
<string name="key__phone_pause" comment="Label for the Pause key in the telephone keyboard layout">Rawesandin</string>
<string name="key__phone_wait" comment="Label for the Wait key in the telephone keyboard layout">Wendeman</string>
<string name="key_popup__threedots_alt" comment="Content description for the three-dots icon in a key popup">Îkona sê-dot. Eger xuya be, nîşan dide ku eger zêdetir pêl bê kirin, zêdetir tîp dikarin bên bikaranîn.</string>
@@ -73,6 +74,7 @@
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">Ji kerema xwe re navekî dirbê têkeve.</string>
<string name="settings__theme__group_keyboard" comment="Theme group label">Klavye</string>
<string name="settings__theme__group_key" comment="Theme group label">Kilîd</string>
<string name="settings__theme__group_privateMode" comment="Theme group label">Moda taybet</string>
<string name="settings__theme__attr_background" comment="Theme attribute label">Rengê Paşrûyê</string>
<string name="settings__theme__attr_foreground" comment="Theme attribute label">Rengê rûerdê</string>
<string name="settings__theme__attr_foregroundAlt" comment="Theme attribute label">Rengê rûerdê (Altêrnatîf)</string>
@@ -114,4 +116,5 @@
<string name="assets__action__export">Hinardin</string>
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -27,9 +27,22 @@
<string name="emoji__category__flags" comment="Emoji category name">깃발</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>
<!-- Settings UI strings -->
<string name="settings__navigation__home" comment="Long-press hint of bottom nav item Home in Settings"></string>
<string name="settings__navigation__keyboard" comment="Long-press hint of bottom nav item Keyboard in Settings">키보드</string>
<string name="settings__navigation__theme" comment="Long-press hint of bottom nav item Theme 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__localization__subtype_add" comment="Subtype dialog add button">추가</string>
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">하위 유형 추가</string>
<string name="settings__localization__subtype_apply" comment="Subtype dialog apply button">적용</string>
<string name="settings__localization__subtype_cancel" comment="Subtype dialog cancel button">취소</string>
<string name="settings__localization__subtype_delete" comment="Subtype dialog delete button">삭제</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>
<!-- About UI strings -->
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -59,7 +59,7 @@
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">Pievienot apakšveidu</string>
<string name="settings__localization__subtype_apply" comment="Subtype dialog apply button">Pielietot</string>
<string name="settings__localization__subtype_cancel" comment="Subtype dialog cancel button">Atcelt</string>
<string name="settings__localization__subtype_delete" comment="Subtype dialog delete button">Dzēst</string>
<string name="settings__localization__subtype_delete" comment="Subtype dialog delete button">Izdzēst</string>
<string name="settings__localization__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">Labot apakšveidu</string>
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Lokalizācija</string>
<string name="settings__localization__subtype_layout" comment="Label for keyboard layout dropdown in subtype dialog">Tastatūras izkārtojums</string>
@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Izveidot no izvēlētā izskata</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Pielāgots (no %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Jauns izskats</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Izskats veiksmīgi ievietots!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Izskats veiksmīgi izdots!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Labot izskatu</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nosaukums</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Veids</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Labot kopu</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Pievienot pazīmi</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Labot pazīmi</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Labot izskata nosaukumu</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Saikne</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Kopa</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Pazīme</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Fonta izmēra reizinātājs (statenisks novietojums)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Fonta izmēra reizinātājs (līmenisks novietojums)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Izkārtojums</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Vienrocīga ievade</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Vienrocīga ievade</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Izslēgts</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Ievade ar labo roku</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Ievade ar kreiso roku</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Vienrocīgās ievades tastatūras platums</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Līmeniska pilnekrāna ievade</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Nekad nerādīt</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Vienmēr rādīt</string>
@@ -190,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Uznirstošā lodziņa redzamība</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Rādīt uznirstošo lodziņu, kad tiek nospiests taustiņš</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Ilgas taustiņa piespiešanas aizture</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Atstarpes taustiņš pārslēdz uz burtu izkārtojumu</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Atstarpes taustiņa nospiešana nomaina izkārtojumu no rakstzīmēm vai cipariem uz burtiem</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Rakstīšanas pieredze</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Iespējot viedjoslu</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Tiks rādīta tastatūras augšpusē</string>
@@ -211,9 +217,9 @@
<string name="pref__gestures__space_bar_title" comment="Preference group title">Atstarpes taustiņa kustības</string>
<string name="pref__gestures__other_title" comment="Preference group title">Citas kustības / Kustību sliekšņi</string>
<string name="pref__gestures__swipe_action__no_action" comment="Preference value for swipe action">Nav darbības</string>
<string name="pref__gestures__swipe_action__delete_characters_precisely" comment="Preference value for swipe action">Dzēst rakstzīmes rūpīgi</string>
<string name="pref__gestures__swipe_action__delete_word" comment="Preference value for swipe action">Dzēst pašreizējo vārdu</string>
<string name="pref__gestures__swipe_action__delete_words_precisely" comment="Preference value for swipe action">Dzēst vārdus rūpīgi</string>
<string name="pref__gestures__swipe_action__delete_characters_precisely" comment="Preference value for swipe action">Rūpīgi izdzēst rakstzīmes</string>
<string name="pref__gestures__swipe_action__delete_word" comment="Preference value for swipe action">Izdzēst pašreizējo vārdu</string>
<string name="pref__gestures__swipe_action__delete_words_precisely" comment="Preference value for swipe action">Rūpīgi izdzēst vārdus</string>
<string name="pref__gestures__swipe_action__hide_keyboard" comment="Preference value for swipe action">Paslēpt tastatūru</string>
<string name="pref__gestures__swipe_action__insert_space" comment="Preference value for swipe action">Ievietot atstarpi</string>
<string name="pref__gestures__swipe_action__move_cursor_up" comment="Preference value for swipe action">Pārvietot rādītāju uz augšu</string>
@@ -237,7 +243,7 @@
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Pavilkt no atstarpes taustiņa pa kreisi</string>
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Pavilkt no atstarpes taustiņa pa labi</string>
<string name="pref__gestures__space_bar_long_press__label" comment="Preference title">Atstarpes taustiņa ilga piespiešana</string>
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Pavilkt no dzēšanas taustiņa pa kreisi</string>
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Pavilkt no izdzēšanas taustiņa pa kreisi</string>
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Pavilkšanas ātruma slieksnis</string>
<string name="pref__gestures__swipe_velocity_threshold__very_slow" comment="Preference value for swipe velocity threshold">Ļoti lēns</string>
<string name="pref__gestures__swipe_velocity_threshold__slow" comment="Preference value for swipe velocity threshold">Lēns</string>
@@ -276,16 +282,18 @@
<string name="assets__action__cancel">Atcelt</string>
<string name="assets__action__cancel_confirm_title">Apstiprināt atcelšanu</string>
<string name="assets__action__cancel_confirm_message">Vai tiešām atmest nesaglabātās izmaiņas? Šī darbība pēc izpildīšanas vairs nevar tikt atsaukta.</string>
<string name="assets__action__delete">Dzēst</string>
<string name="assets__action__delete_confirm_title">Apstiprināt dzēšanu</string>
<string name="assets__action__delete_confirm_message">Vai tiešām dzēst \"%s\"? Šī darbība pēc izpildīšanas vairs nevar tikt atsaukta.</string>
<string name="assets__action__delete">Izdzēst</string>
<string name="assets__action__delete_confirm_title">Apstiprināt izdzēšanu</string>
<string name="assets__action__delete_confirm_message">Vai tiešām izdzēst \"%s\"? Šī darbība pēc izpildīšanas vairs nevar tikt atsaukta.</string>
<string name="assets__action__edit">Labot</string>
<string name="assets__action__export">Izdot</string>
<string name="assets__action__import">Iekļaut</string>
<string name="assets__action__no"></string>
<string name="assets__action__save">Saglabāt</string>
<string name="assets__action__yes"></string>
<string name="assets__error__details">Izklāsts</string>
<string name="assets__error__invalid">Nederīgs</string>
<string name="assets__error__snackbar_message">Kaut kas ir noticis nepareizi</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Iestatīšana</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Iepriekšējais</string>
@@ -319,4 +327,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Pieskarties, lai apskatītu kļudu izklāstu</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Izskatās, ka FlorisBoard atkārtoti pārstāj darboties…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Notiek atkāpšanāš uz iepriekšējo tastatūru, lai apturētu nebeidzamu avārijas cilpu. Piesist, lai apskatītu kļūdu izklāstu</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Pārslēgties uz starpliktuves vēsturi</string>
<string name="clip__context_header">Starpliktuves vēsture</string>
<string name="clip__clear_history">Notīrīt vēsturi</string>
<string name="clip__unpin_item">Atspraust vienumu</string>
<string name="clip__pin_item">Piespraust vienumu</string>
<string name="clip__delete_item">Izdzēst</string>
<string name="clip__paste_item">Ielīmēt</string>
<string name="clip__back_to_text_input">Atgriezties pie teksta ievades</string>
<string name="clip__cant_paste">Pašreizējā lietotne neļauj ielīmēt šo saturu.</string>
</resources>

View File

@@ -40,4 +40,5 @@
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -160,7 +160,7 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Factor lettergrootte (portret-modus)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Factor lettergrootte (landschapsmodus)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Indeling</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Eenhandige modus</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Eenhandige modus</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Uit</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Rechtshandige modus</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Linkshandige modus</string>
@@ -310,4 +310,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Tik om foutdetails te bekijken</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard lijkt herhaaldelijk te stoppen met werken…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Terugvallen op het vorige toetsenbord om oneindige crash-loop te stoppen. Tik om foutdetails te bekijken</string>
<!-- clipboard strings -->
</resources>

View File

@@ -13,4 +13,5 @@
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -160,7 +160,7 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Mnożnik rozmiaru czcionki (portret)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Mnożnik rozmiaru czcionki (krajobraz)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Układ</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Tryb jednoręczny</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Tryb jednoręczny</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Wyłącz</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Tryb praworęczny</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Tryb leworęczny</string>
@@ -316,4 +316,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Kliknij, by zobaczyć szczegóły</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard wydaje się wielokrotnie przerywać pracę…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Powracanie do poprzedniej klawiatury w celu zatrzymania nieskończonej pętli awarii. Stuknij, aby wyświetlić szczegóły błędu</string>
<!-- clipboard strings -->
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Criar a partir do tema selecionado</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Personalizado (baseado no %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Novo tema</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Tema importado com sucesso!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Tema exportado com sucesso!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Editar tema</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nome</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Tipo</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Editar grupo</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Adicionar atributo</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Editar atributo</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Editar o nome do tema</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Referência</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Grupo</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atributo</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplicador de tamanho da fonte (retrato)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplicador de tamanho da fonte (paisagem)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Layout</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Modo uma mão</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Modo uma mão</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Desligado</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Modo destro</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Modo canhoto</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Largura do teclado no modo uma mão</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Entrada do modo paisagem em tela cheia</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Nunca mostrar</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Sempre mostrar</string>
@@ -190,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Visibilidade do PopUp</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Mostrar popup quando pressionar uma tecla</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Atraso ao pressionar e segurar uma tecla</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Barra de espaço muda de volta para o layout de caracteres</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Apertar e segurar a barra de espaço muda automaticamente para os caracteres quando em símbolos ou números</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Experiência de digitação</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Ativar barra inteligente</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Mostrar na parte superior do teclado</string>
@@ -284,7 +290,9 @@
<string name="assets__action__no">Não</string>
<string name="assets__action__save">Salvar</string>
<string name="assets__action__yes">Sim</string>
<string name="assets__error__details">Detalhes</string>
<string name="assets__error__invalid">Inválido</string>
<string name="assets__error__snackbar_message">Algo deu errado</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Configurar</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Anterior</string>
@@ -318,4 +326,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Toque para ver os detalhes do erro</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard parece parar de funcionar repetidamente…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Recuando para o teclado anterior para parar o loop infinito de travamento. Toque para ver os detalhes do erro</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Mudar para o histórico da área de transferência</string>
<string name="clip__context_header">Histórico da área de transferência</string>
<string name="clip__clear_history">Limpar histórico</string>
<string name="clip__unpin_item">Desfixar item</string>
<string name="clip__pin_item">Fixar item</string>
<string name="clip__delete_item">Excluir</string>
<string name="clip__paste_item">Colar</string>
<string name="clip__back_to_text_input">Voltar para a entrada de texto</string>
<string name="clip__cant_paste">Este aplicativo não permite colar esse conteúdo.</string>
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Criar a partir do tema atual</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Personalizado (baseado em %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Novo tema</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Tema importado com sucesso!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Tema exportado com sucesso!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Editar tema</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nome</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Tipo</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Editar grupo</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Adicionar atributo</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Editar atributo</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Editar nome do tema</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Referência</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Grupo</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atributo</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplicador do tamanho do tipo de letra (vertical)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplicador do tamanho do tipo de letra (horizontal)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Disposição</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Modo de uma mão</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Modo de uma mão</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Desligado</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Modo destro</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Modo esquerdino</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Largura do teclado no modo de uma mão</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Introdução em ecrã completo (horizontal)</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Nunca mostrar</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Mostrar sempre</string>
@@ -190,6 +194,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Destaque de teclas</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Ampliar caracteres ao premir uma tecla</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Atraso para a pressão longa de teclas</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Barra de espaço alterna para a disposição de caracteres</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Ao premir a barra de espaço, alternar automaticamente para caracteres se em símbolos ou números</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Experiência de digitação</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Ativar barra inteligente</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Mostrar na parte superior do teclado</string>
@@ -284,7 +290,9 @@
<string name="assets__action__no">Não</string>
<string name="assets__action__save">Guardar</string>
<string name="assets__action__yes">Sim</string>
<string name="assets__error__details">Detalhes</string>
<string name="assets__error__invalid">Inválido</string>
<string name="assets__error__snackbar_message">Algo errado aconteceu!</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Configuração</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Recuar</string>
@@ -318,4 +326,14 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Toque para ver os detalhes do erro</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Parece que FlorisBoard não está a funcionar muito bem…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">A ativar o teclado usado anteriormente para parar este ciclo. Toque para ver os detalhes do erro.</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Ir para histórico da área de transferência</string>
<string name="clip__context_header">Histórico da área de transferência</string>
<string name="clip__clear_history">Limpar histórico</string>
<string name="clip__unpin_item">Desafixar item</string>
<string name="clip__pin_item">Fixar item</string>
<string name="clip__delete_item">Remover</string>
<string name="clip__paste_item">Colar</string>
<string name="clip__back_to_text_input">Voltar para a introdução de texto</string>
<string name="clip__cant_paste">A aplicação não permite a colagem deste conteúdo.</string>
</resources>

View File

@@ -32,7 +32,7 @@
<string name="smartbar__quick_action__exit_editing" comment="Content-description for the exit editing layout button in Smartbar">Закрыть панель редактирования текста.</string>
<string name="smartbar__quick_action__one_handed_mode" comment="Content-description for the one-handed quick action 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_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>
<string name="smartbar__quick_action__undo" comment="Content-description for the undo quick action in Smartbar">Кнопка \"Отменить\" для отмены последнего действия</string>
<string name="smartbar__quick_action__redo" comment="Content-description for the redo quick action in Smartbar">Кнопка \"Повтор\", чтобы отменить последнее \"Отменить\"</string>
@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Создать из выбранной темы</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Пользовательский (основан на %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Новая тема</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Тема успешно импортирована!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Тема успешно экспортирована!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Редактировать тему</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Название</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Тип</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Редактировать группу</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Добавить атрибут</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Редактировать атрибут</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Изменить название темы</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Источник</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Группа</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Атрибут</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Мультипликатор размера шрифта (портрет)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">Управление одной рукой</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Управление одной рукой</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Выкл</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Режим правши</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Режим левши</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__landscape_input_ui_mode__never_show" comment="Preference value">Никогда не показывать</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Показывать всегда</string>
@@ -222,6 +226,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Переместить курсор вправо</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Переместить курсор в начало строки</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Переместить курсор в конец строки</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Переместить курсор в начало страницы</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Переместить курсор в конец страницы</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Shift</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Показать способ ввода</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Переключиться на предыдущую клавиатуру</string>
@@ -284,7 +290,9 @@
<string name="assets__action__no">Нет</string>
<string name="assets__action__save">Сохранить</string>
<string name="assets__action__yes">Да</string>
<string name="assets__error__details">Детали</string>
<string name="assets__error__invalid">Ошибка</string>
<string name="assets__error__snackbar_message">Что-то пошло не так</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Настройка</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Пред.</string>
@@ -318,4 +326,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Нажмите, чтобы увидеть детали об ошибке</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Кажется, FlorisBoard постоянно перестаёт работать…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Возвращение к предыдущей клавиатуре, чтобы остановить бесконечный цикл сбоя. Нажмите, чтобы просмотреть детали об ошибке</string>
<!-- clipboard strings -->
</resources>

View File

@@ -13,4 +13,5 @@
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -13,4 +13,5 @@
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -61,4 +61,5 @@
<!-- Assets strings -->
<!-- Setup UI strings -->
<!-- Crash Dialog strings -->
<!-- clipboard strings -->
</resources>

View File

@@ -132,7 +132,7 @@
<string name="pref__keyboard__number_row__summary" comment="Preference summary">Visa sifferraden ovanför tecken layouten</string>
<string name="pref__keyboard__hint_mode__disabled" comment="Preference value">Inaktiverad</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Layout</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference value">Enhandsläge</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Enhandsläge</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Av</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Högerhandsläge</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Vänsterhandsläge</string>
@@ -217,4 +217,5 @@
<!-- Crash Dialog strings -->
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">Kopiera till urklipp</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Stäng</string>
<!-- clipboard strings -->
</resources>

View File

@@ -87,6 +87,8 @@
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Створити з поточної теми</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Користувацька (на основі %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Нова тема</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Тема успішно імпортована!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Тема успішно експортована!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Редагувати тему</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Назва</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Тип</string>
@@ -94,6 +96,7 @@
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Редагувати групу</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Додати атрибут</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Редагувати атрибут</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Змінити назву теми</string>
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Посилання</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Група</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Атрибут</string>
@@ -160,10 +163,11 @@
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Мультиплікатор розміру шрифту (портрет)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__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 value">Керування однією рукою</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Керування однією рукою</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Вимк</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Режим правші</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Режим лівші</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__landscape_input_ui_mode__never_show" comment="Preference value">Ніколи не відображати</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Завжди відображати</string>
@@ -222,6 +226,8 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Перемістити курсор вправо</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Перемістити курсор на початок рядку</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Перемістити курсор в кінець рядку</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Перемістити курсор на початок тексту</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Перемістити курсор в кінець тексту</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Shift</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Показати вибір методу вводу</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Перемикнутись на попередню клавіатуру</string>
@@ -284,7 +290,9 @@
<string name="assets__action__no">Ні</string>
<string name="assets__action__save">Зберегти</string>
<string name="assets__action__yes">Так</string>
<string name="assets__error__details">Деталі</string>
<string name="assets__error__invalid">Помилка</string>
<string name="assets__error__snackbar_message">Щось пішло не так</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Налаштування</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Назад</string>
@@ -318,4 +326,5 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Натисність, щоб перегянути деталі про помилку</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Здається, FlorisBoard постійно перестає працювати…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Повернення до попередньої клавіатури, щоб зупинити нескінченний цикл збою. Натисніть, щоб переглянути деталі про помилку</string>
<!-- clipboard strings -->
</resources>

View File

@@ -39,4 +39,5 @@
<string name="setup__welcome__title" comment="Title of Welcome fragment in Setup">ⴱⵔⵔⴽ!</string>
<!-- Crash Dialog strings -->
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">ⵔⴳⵍ</string>
<!-- clipboard strings -->
</resources>

View File

@@ -98,6 +98,7 @@
<item>@string/pref__gestures__swipe_action__switch_to_prev_subtype</item>
<item>@string/pref__gestures__swipe_action__switch_to_next_subtype</item>
<item>@string/pref__gestures__swipe_action__switch_to_prev_keyboard</item>
<item>@string/pref__gestures__swipe_action__switch_to_clipboard_context</item>
</string-array>
<string-array name="pref__gestures__swipe_action__values">
<item>no_action</item>
@@ -117,6 +118,7 @@
<item>switch_to_prev_subtype</item>
<item>switch_to_next_subtype</item>
<item>switch_to_prev_keyboard</item>
<item>switch_to_clipboard_context</item>
</string-array>
<string-array name="pref__gestures__swipe_action_delete__entries">
@@ -174,4 +176,15 @@
<item>follow_system</item>
<item>follow_time</item>
</string-array>
<string-array name="pref__suggestion__display_mode__entries">
<item>@string/pref__suggestion__display_mode__classic</item>
<item>@string/pref__suggestion__display_mode__dynamic</item>
<item>@string/pref__suggestion__display_mode__dynamic_scrollable</item>
</string-array>
<string-array name="pref__suggestion__display_mode__values">
<item>classic</item>
<item>dynamic</item>
<item>dynamic_scrollable</item>
</string-array>
</resources>

View File

@@ -38,6 +38,9 @@
<dimen name="media_tab_indicator_height">4dp</dimen>
<dimen name="media_tab_paddingH">0dp</dimen>
<dimen name="clipboard_button_width">60dp</dimen>
<dimen name="clipboard_button_height">@dimen/key_height</dimen>
<dimen name="one_handed_width">50dp</dimen>
<dimen name="one_handed_button_width">@dimen/one_handed_width</dimen>
<dimen name="one_handed_button_height">@dimen/one_handed_width</dimen>
@@ -46,6 +49,9 @@
<dimen name="smartbar_radius">20dp</dimen>
<dimen name="smartbar_button_margin">4dp</dimen>
<dimen name="smartbar_button_padding">6dp</dimen>
<dimen name="smartbar_candidate_textSize">14sp</dimen>
<dimen name="smartbar_candidate_marginH">16dp</dimen>
<dimen name="smartbar_divider_width">1dp</dimen>
<dimen name="fab_margin">16dp</dimen>
@@ -54,6 +60,7 @@
<dimen name="gesture_distance_threshold_normal">32dp</dimen>
<dimen name="gesture_distance_threshold_long">36dp</dimen>
<dimen name="gesture_distance_threshold_very_long">40dp</dimen>
<dimen name="clipboard_text_item_pin_margin" >25dp</dimen>
<integer name="gesture_velocity_threshold_very_slow">50</integer>
<integer name="gesture_velocity_threshold_slow">60</integer>

View File

@@ -210,6 +210,8 @@
<string name="pref__keyboard__popup_visible__label" comment="Preference title">PopUp Visibility</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Show popup when you press a key</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Long key press delay</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Space bar switches back to character layout</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Pressing space bar automatically switches back to characters when in symbols or numeric</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Typing experience</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Enable Smartbar</string>
@@ -221,8 +223,13 @@
<string translatable="false" name="pref__suggestion__use_pref_words__summary" comment="Preference summary">Use previous words for generating suggestions</string>
<string translatable="false" name="pref__suggestion__block_possibly_offensive__label" comment="Preference title">[EXPERIMENTAL] Block possibly offensive words</string>
<string translatable="false" name="pref__suggestion__block_possibly_offensive__summary" comment="Preference summary">Prevents possibly offensive words from being suggested while you type</string>
<string translatable="false" name="pref__suggestion__suggest_clipboard_content__label" comment="Preference title">[EXPERIMENTAL] Clipboard content suggestions</string>
<string translatable="false" name="pref__suggestion__suggest_clipboard_content__summary" comment="Preference summary">Suggest clipboard content to paste if previously copied</string>
<string translatable="false" name="pref__suggestion__clipboard_content_enabled__label" comment="Preference title">[EXPERIMENTAL] Clipboard content suggestions</string>
<string translatable="false" name="pref__suggestion__clipboard_content_enabled__summary" comment="Preference summary">Suggest clipboard content to paste if previously copied</string>
<string translatable="false" name="pref__suggestion__clipboard_content_timeout__label" comment="Preference title">[EXPERIMENTAL] Clipboard suggestion timeout</string>
<string translatable="false" name="pref__suggestion__display_mode__label" comment="Preference title">[EXPERIMENTAL] Suggestions display mode</string>
<string translatable="false" name="pref__suggestion__display_mode__classic" comment="Preference value">Classic (3 columns)</string>
<string translatable="false" name="pref__suggestion__display_mode__dynamic" comment="Preference value">Dynamic width</string>
<string translatable="false" name="pref__suggestion__display_mode__dynamic_scrollable" comment="Preference value">Dynamic width &amp; scrollable</string>
<string name="pref__correction__title" comment="Preference group title">Corrections</string>
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Auto-capitalization</string>
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Capitalize words based on the current input context</string>
@@ -360,4 +367,15 @@
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Tap to view error details</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard seems to stop working repeatedly…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Falling back to previous keyboard to stop infinite crash loop. Tap to view error details</string>
<!-- clipboard strings -->
<string name="pref__gestures__swipe_action__switch_to_clipboard_context">Switch to clipboard history</string>
<string name="clip__context_header">Clipboard history</string>
<string name="clip__clear_history">Clear history</string>
<string name="clip__unpin_item">Unpin item</string>
<string name="clip__pin_item">Pin item</string>
<string name="clip__delete_item">Delete</string>
<string name="clip__paste_item">Paste</string>
<string name="clip__back_to_text_input">Back to text input</string>
<string name="clip__cant_paste">This app doesn\'t allow pasting this content.</string>
</resources>

View File

@@ -1,17 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="SmartbarCandidate">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_weight">1</item>
<item name="android:background">@drawable/button_transparent_bg_on_press</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:gravity">center</item>
<item name="android:textAllCaps">false</item>
<item name="android:textStyle">normal</item>
</style>
<style name="SmartbarContainer">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
@@ -19,15 +8,6 @@
<item name="android:orientation">horizontal</item>
</style>
<style name="SmartbarDivider">
<item name="android:layout_width">1dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_weight">0</item>
<item name="android:layout_marginTop">@dimen/smartbar_button_margin</item>
<item name="android:layout_marginBottom">@dimen/smartbar_button_margin</item>
<item name="android:background">?semiTransparentColor</item>
</style>
<style name="SmartbarQuickAction" parent="Widget.AppCompat.Button">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">match_parent</item>
@@ -39,17 +19,6 @@
<item name="android:tint">#000000</item>
</style>
<style name="SmartbarQuickAction.ClipboardSuggestion">
<item name="android:layout_width">200dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:background">@drawable/shape_rect_rounded_2</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">marquee</item>
<item name="android:fadingEdge">horizontal</item>
<item name="android:textAllCaps">false</item>
<item name="android:textStyle">normal</item>
</style>
<style name="SmartbarQuickAction.Toggle">
<item name="android:autoMirrored">true</item>
</style>

View File

@@ -232,6 +232,87 @@
app:seekBarIncrement="10"
app:unit=" ms"/>
<SwitchPreferenceCompat
android:defaultValue="true"
app:key="keyboard__space_bar_switches_to_characters"
app:iconSpaceReserved="false"
app:title="@string/pref__keyboard__space_bar_switches_to_characters__label"
app:summary="@string/pref__keyboard__space_bar_switches_to_characters__summary"/>
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"
android:title="Clipboard">
<SwitchPreferenceCompat
android:defaultValue="true"
app:key="clipboard__enable_internal"
app:iconSpaceReserved="false"
app:title="Use internal clipboard"
app:summary="Use an internal clipboard instead of the system clipboard"/>
<SwitchPreferenceCompat
android:dependency="clipboard__enable_internal"
android:defaultValue="true"
app:key="clipboard__sync_to_floris"
app:iconSpaceReserved="false"
app:title="Sync from system clipboard"
app:summary="System clipboard updates also update Floris clipboard"/>
<SwitchPreferenceCompat
android:dependency="clipboard__enable_internal"
android:defaultValue="false"
app:key="clipboard__sync_to_system"
app:iconSpaceReserved="false"
app:title="Sync to system clipboard"
app:summary="Floris clipboard updates also update system clipboard"/>
<SwitchPreferenceCompat
android:defaultValue="false"
app:key="clipboard__enable_history"
app:iconSpaceReserved="false"
app:title="Enable clipboard history"
app:summary="Retain clipboard items"/>
<SwitchPreferenceCompat
android:dependency="clipboard__enable_history"
android:defaultValue="true"
app:key="clipboard__clean_up_old"
app:iconSpaceReserved="false"
app:title="Clean up old items" />
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
app:allowDividerAbove="false"
android:dependency="clipboard__clean_up_old"
android:defaultValue="15"
app:key="clipboard__clean_up_after"
app:min="0"
app:max="120"
app:iconSpaceReserved="false"
app:title="Clean up old items after"
app:seekBarIncrement="5"
app:unit=" minutes"/>
<SwitchPreferenceCompat
android:dependency="clipboard__enable_history"
android:defaultValue="true"
app:key="clipboard__limit_history_size"
app:iconSpaceReserved="false"
app:title="Limit history size" />
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
app:allowDividerAbove="false"
android:dependency="clipboard__limit_history_size"
android:defaultValue="25"
app:key="clipboard__max_history_size"
app:min="5"
app:max="100"
app:iconSpaceReserved="false"
app:title="Max history size"
app:seekBarIncrement="5"
app:unit=" items"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -21,6 +21,16 @@
app:title="@string/pref__suggestion__enabled__label"
app:summary="@string/pref__suggestion__enabled__summary"/>
<ListPreference
android:defaultValue="dynamic_scrollable"
app:dependency="suggestion__enabled"
app:entries="@array/pref__suggestion__display_mode__entries"
app:entryValues="@array/pref__suggestion__display_mode__values"
app:key="suggestion__display_mode"
app:iconSpaceReserved="false"
app:title="@string/pref__suggestion__display_mode__label"
app:useSimpleSummaryProvider="true"/>
<SwitchPreferenceCompat
android:defaultValue="true"
app:dependency="suggestion__enabled"
@@ -40,10 +50,22 @@
<SwitchPreferenceCompat
android:defaultValue="true"
app:dependency="suggestion__enabled"
app:key="suggestion__suggest_clipboard_content"
app:key="suggestion__clipboard_content_enabled"
app:iconSpaceReserved="false"
app:title="@string/pref__suggestion__suggest_clipboard_content__label"
app:summary="@string/pref__suggestion__suggest_clipboard_content__summary"/>
app:title="@string/pref__suggestion__clipboard_content_enabled__label"
app:summary="@string/pref__suggestion__clipboard_content_enabled__summary"/>
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
app:allowDividerAbove="false"
android:defaultValue="60"
app:dependency="suggestion__clipboard_content_enabled"
app:key="suggestion__clipboard_content_timeout"
app:min="30"
app:max="150"
app:iconSpaceReserved="false"
app:title="@string/pref__suggestion__clipboard_content_timeout__label"
app:seekBarIncrement="5"
app:unit=" s"/>
</PreferenceCategory>

View File

@@ -26,7 +26,7 @@ class NgramNodeTest {
@Test
fun findWord_returnsCorrectNode_forExistingWord() {
val expected = ngramTreeToBeTested.higherOrderChildren['t']?.sameOrderChildren?.get('h')?.sameOrderChildren?.get('e')
val expected = ngramTreeToBeTested.higherOrderChildren['t'].sameOrderChildren.get('h').sameOrderChildren.get('e')
val actual = ngramTreeToBeTested.findWord("the")
assertThat(actual, `is`(expected))
}
@@ -50,7 +50,7 @@ class NgramNodeTest {
@Test
fun listAllSameOrderWords_returnsCorrectList_forGivenPrefix() {
val words = StagedSuggestionList<String, Int>(4)
ngramTreeToBeTested.higherOrderChildren['t']?.listAllSameOrderWords(words, true)
ngramTreeToBeTested.higherOrderChildren['t'].listAllSameOrderWords(words, true)
assertThat(
words,
`is`(StagedSuggestionList<String, Int>(4).apply {
@@ -63,5 +63,4 @@ class NgramNodeTest {
}
}
class FlorisLanguageModelTest {
}
class FlorisLanguageModelTest

View File

@@ -15,4 +15,5 @@
<li>Customizable actions for gestures: swipe up/down/left/right, space bar left/right, delete key swipe)</li>
<li>Integrated special symbols into character layouts</li>
<li>Clipboard/Cursor toolbar</li>
<li>Clipboard manager/history</li>
</ul>

View File

@@ -0,0 +1,2 @@
- Stub release for initialing beta-track properly
- Release code is identical to v0.3.9

View File

@@ -0,0 +1,8 @@
- Add clipboard manager / history (#454, thanks @X-yl)
- Manage your clipboard entries in a modern and organized UI
- Automatic clearing of items after specified time
- Pin items to the top
- Enable/disable sync with Android clipboard
- Support for copy/paste of images (does not work in all apps though)
- Fix import theme crash for big files (#465)
- Fix symbols layouts applying the caps state once again (#298)

View File

@@ -0,0 +1,6 @@
- Add Turkish-Q / Turkish-F layouts (#182)
- Add Gboard Night theme (#486, thanks @Netscaping)
- Add auto-switching to characters in symbols (#347)
- Fix Ž key not available in Dvorak/Serbian (#381)
- Fix language selector size for keyboard height greater than 125% (#129)
- Rework symbols sizing when number row is enabled (#482)

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