Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddc4f7f1ba | ||
|
|
afea8c721f | ||
|
|
7dedfd4f7a | ||
|
|
ef37194900 | ||
|
|
58134b1ceb | ||
|
|
53cfbad404 | ||
|
|
9cffcea246 | ||
|
|
5acf80db0f | ||
|
|
d6f724e518 | ||
|
|
6c4aa36b06 | ||
|
|
edc38b6c2c | ||
|
|
891a2c6bac | ||
|
|
229237153b | ||
|
|
290fbb5239 | ||
|
|
409d4f9348 | ||
|
|
82938cda5b | ||
|
|
f7b0a30271 | ||
|
|
575f359a85 | ||
|
|
22591163b3 | ||
|
|
8104ae60ca | ||
|
|
165b682732 | ||
|
|
eb770fac6c | ||
|
|
39c27426a4 | ||
|
|
228d5055cc | ||
|
|
b400e04560 | ||
|
|
27c1bbf039 | ||
|
|
f61b655f7d | ||
|
|
f82af63e97 | ||
|
|
0fbd950f6e | ||
|
|
e97b5f54ac | ||
|
|
b611360dd5 | ||
|
|
1b9d260020 | ||
|
|
d74fe62bc0 | ||
|
|
fe6f61a282 | ||
|
|
8b4239d9be | ||
|
|
a0c7cf2794 | ||
|
|
7480d14a0f | ||
|
|
7274228a46 | ||
|
|
a38f6a2c76 | ||
|
|
eda6c09538 | ||
|
|
9e42d16cb0 | ||
|
|
11ba51c354 | ||
|
|
51f5196b8a | ||
|
|
56bbe9d13c | ||
|
|
4d1ae52dc0 | ||
|
|
1e1916194b |
@@ -9,7 +9,7 @@ insert_final_newline = true
|
||||
max_line_length = 120
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.har,*.json,*yml}]
|
||||
[{*.har,*.json,*yml,*.sh}]
|
||||
indent_size = 2
|
||||
|
||||
[*.kt]
|
||||
|
||||
2
.github/workflows/crowdin-upload.yml
vendored
2
.github/workflows/crowdin-upload.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Upload
|
||||
uses: crowdin/github-action@1.4.0
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
config: "crowdin.yml"
|
||||
upload_sources: true
|
||||
|
||||
61
.github/workflows/validate-strings-no-translations.yml
vendored
Normal file
61
.github/workflows/validate-strings-no-translations.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Validate no translated strings.xml included
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Precheck if validation is required
|
||||
id: precheck
|
||||
run: |
|
||||
pr_author="${{ github.event.pull_request.user.login }}"
|
||||
if [[ "$pr_author" == "florisboard-bot" ]]; then
|
||||
echo "PR is by florisboard-bot, skipping validation!"
|
||||
echo "require_validation=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "PR is not by florisboard-bot, requiring validation!"
|
||||
echo "require_validation=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Fetch PR changed files manually
|
||||
id: fetch_changed_files
|
||||
if: steps.precheck.outputs.require_validation == 'true'
|
||||
run: |
|
||||
pr_files="$(curl -sSf https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files?per_page=1000)" || exit 11
|
||||
changed_files="$(jq -r '.[].filename' <<< "$pr_files")" || exit 12
|
||||
illegal_changes_list="$(grep -E '^app/src/main/res/values-.+/strings.xml$' <<< "$changed_files")" || true
|
||||
if [ -n "$illegal_changes_list" ]; then
|
||||
echo -e "Illegal changes detected:\n$illegal_changes_list"
|
||||
else
|
||||
echo "No illegal changes detected"
|
||||
fi
|
||||
echo "illegal_changes_list<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$illegal_changes_list" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create comment if illegal files detected
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
if: steps.precheck.outputs.require_validation == 'true' && steps.fetch_changed_files.outputs.illegal_changes_list != ''
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
⚠️ Illegal changes detected
|
||||
|
||||
Hey there!
|
||||
|
||||
We detected illegal changes that disobey the [contribution guidelines](https://github.com/florisboard/florisboard/blob/main/CONTRIBUTING.md#translation). This is a kind reminder that pull requests must not contain translated `strings.xml` files, as those are exclusively managed from Crowdin.
|
||||
|
||||
Please remove changes to the following files:
|
||||
```
|
||||
${{ steps.fetch_changed_files.outputs.illegal_changes_list }}
|
||||
```
|
||||
|
||||
- name: Fail workflow if illegal files detected
|
||||
if: steps.precheck.outputs.require_validation == 'true' && steps.fetch_changed_files.outputs.illegal_changes_list != ''
|
||||
run: echo -e "Illegal changes detected:\n${{ steps.fetch_changed_files.outputs.illegal_changes_list }}" && exit 1
|
||||
30
README.md
30
README.md
@@ -1,7 +1,7 @@
|
||||
<img align="left" width="80" height="80"
|
||||
src=".github/repo_icon.png" alt="App icon">
|
||||
|
||||
# FlorisBoard [](https://crowdin.florisboard.patrickgold.dev) [](https://matrix.to/#/#florisboard:matrix.org) [](CODE_OF_CONDUCT.md) 
|
||||
# FlorisBoard [](https://crowdin.florisboard.patrickgold.dev) [](https://matrix.to/#/#florisboard:matrix.org) [](CODE_OF_CONDUCT.md) [](https://github.com/florisboard/florisboard/actions/workflows/android.yml)
|
||||
|
||||
**FlorisBoard** is a free and open-source keyboard for Android 7.0+
|
||||
devices. It aims at being modern, user-friendly and customizable while
|
||||
@@ -10,10 +10,10 @@ fully respecting your privacy. Currently in early-beta state.
|
||||
<table>
|
||||
<tr>
|
||||
<th align="center" width="50%">
|
||||
<h3>Stable <a href="https://github.com/florisboard/florisboard/releases/latest"><img alt="Latest stable release" src="https://img.shields.io/github/v/release/florisboard/florisboard"></a></h3>
|
||||
<h3>Stable <a href="https://github.com/florisboard/florisboard/releases/latest"><img alt="Latest stable release" src="https://img.shields.io/github/v/release/florisboard/florisboard?sort=semver&display_name=tag&color=28a745"></a></h3>
|
||||
</th>
|
||||
<th align="center" width="50%">
|
||||
<h3>Beta <a href="https://github.com/florisboard/florisboard/releases"><img alt="Latest beta release" src="https://img.shields.io/github/v/release/florisboard/florisboard?include_prereleases"></a></h3>
|
||||
<h3>Preview <a href="https://github.com/florisboard/florisboard/releases"><img alt="Latest preview release" src="https://img.shields.io/github/v/release/florisboard/florisboard?include_prereleases&sort=semver&display_name=tag&color=fd7e14"></a></h3>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -21,7 +21,7 @@ fully respecting your privacy. Currently in early-beta state.
|
||||
<p><i>Major versions only</i><br><br>Updates are more polished, new features are matured and tested through to ensure a stable experience.</p>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<p><i>Alpha/Beta versions</i><br><br>Updates contain new features that may not be fully matured yet and bugs are more likely to occur. Allows you to give early feedback.</p>
|
||||
<p><i>Major + Alpha/Beta/Rc versions</i><br><br>Updates contain new features that may not be fully matured yet and bugs are more likely to occur. Allows you to give early feedback.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -34,6 +34,11 @@ fully respecting your privacy. Currently in early-beta state.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
**Obtainium**: [Auto-import stable config][obtainium_stable]
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
**Manual**: Download and install the APK from the release page.
|
||||
|
||||
</p>
|
||||
@@ -42,7 +47,12 @@ fully respecting your privacy. Currently in early-beta state.
|
||||
<p><a href="https://apt.izzysoft.de/fdroid/index/apk/dev.patrickgold.florisboard.beta"><img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="64" alt="IzzySoft repo badge"></a></p>
|
||||
<p>
|
||||
|
||||
**Google Play**: Join the [FlorisBoard Test Group](https://groups.google.com/g/florisboard-public-alpha-test), then visit the [beta testing page](https://play.google.com/apps/testing/dev.patrickgold.florisboard.beta). Once joined and installed, updates will be delivered like for any other app. ([Store entry](https://play.google.com/store/apps/details?id=dev.patrickgold.florisboard.beta))
|
||||
**Google Play**: Join the [FlorisBoard Test Group](https://groups.google.com/g/florisboard-public-alpha-test), then visit the [preview testing page](https://play.google.com/apps/testing/dev.patrickgold.florisboard.beta). Once joined and installed, updates will be delivered like for any other app. ([Store entry](https://play.google.com/store/apps/details?id=dev.patrickgold.florisboard.beta))
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
**Obtainium**: [Auto-import preview config][obtainium_preview]
|
||||
|
||||
</p>
|
||||
<p>
|
||||
@@ -54,14 +64,13 @@ fully respecting your privacy. Currently in early-beta state.
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Beginning with v0.4.0 FlorisBoard will follow [SemVer](https://semver.org/#summary) versioning scheme.
|
||||
Beginning with v0.6.0 FlorisBoard will enter the public beta on Google Play.
|
||||
|
||||
## Highlighted features
|
||||
- Integrated clipboard manager / history
|
||||
- Advanced theming support and customization
|
||||
- Integrated extension support (still evolving)
|
||||
- Emoji keyboard
|
||||
- Emoji keyboard / history / suggestions
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Word suggestions/spell checking are not included in the current releases
|
||||
@@ -119,3 +128,10 @@ 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.
|
||||
```
|
||||
|
||||
<!-- BEGIN SECTION: obtainium_links -->
|
||||
<!-- auto-generated link templates, do NOT edit by hand -->
|
||||
<!-- see fastlane/update-readme.sh -->
|
||||
[obtainium_preview]: https://apps.obtainium.imranr.dev/redirect.html?r=obtainium://app/%7B%22id%22%3A%22dev.patrickgold.florisboard.beta%22%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fflorisboard%2Fflorisboard%22%2C%22author%22%3A%22florisboard%22%2C%22name%22%3A%22FlorisBoard%20Preview%22%2C%22additionalSettings%22%3A%22%7B%5C%22includePrereleases%5C%22%3Atrue%2C%5C%22fallbackToOlderReleases%5C%22%3Atrue%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22preview%5C%22%7D%22%7D%0A
|
||||
[obtainium_stable]: https://apps.obtainium.imranr.dev/redirect.html?r=obtainium://app/%7B%22id%22%3A%22dev.patrickgold.florisboard%22%2C%22url%22%3A%22https%3A%2F%2Fgithub.com%2Fflorisboard%2Fflorisboard%22%2C%22author%22%3A%22florisboard%22%2C%22name%22%3A%22FlorisBoard%20Stable%22%2C%22additionalSettings%22%3A%22%7B%5C%22includePrereleases%5C%22%3Afalse%2C%5C%22fallbackToOlderReleases%5C%22%3Atrue%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22stable%5C%22%7D%22%7D%0A
|
||||
<!-- END SECTION: obtainium_links -->
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeFeatureFlag
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.agp.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.plugin.compose)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.mannodermaus.android.junit5)
|
||||
@@ -48,7 +50,6 @@ android {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
freeCompilerArgs = listOf(
|
||||
"-Xallow-result-return-type",
|
||||
"-opt-in=kotlin.contracts.ExperimentalContracts",
|
||||
"-Xjvm-default=all-compatibility",
|
||||
)
|
||||
@@ -99,10 +100,6 @@ android {
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get()
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
named("debug") {
|
||||
applicationIdSuffix = ".debug"
|
||||
@@ -165,14 +162,14 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
composeCompiler {
|
||||
// DO NOT ENABLE STRONG SKIPPING! This project currently relies on
|
||||
// recomposition on parent state change to update the UI correctly.
|
||||
featureFlags.add(ComposeFeatureFlag.StrongSkipping.disabled())
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 3,
|
||||
"identityHash": "282a1b421e498fd0e21c055b6a4315e0",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "clipboard_history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` INTEGER NOT NULL, `text` TEXT, `uri` TEXT, `creationTimestampMs` INTEGER NOT NULL, `isPinned` INTEGER NOT NULL, `mimeTypes` TEXT NOT NULL, `isSensitive` INTEGER NOT NULL, `isRemoteDevice` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "_id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "text",
|
||||
"columnName": "text",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "uri",
|
||||
"columnName": "uri",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "creationTimestampMs",
|
||||
"columnName": "creationTimestampMs",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isPinned",
|
||||
"columnName": "isPinned",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "mimeTypes",
|
||||
"columnName": "mimeTypes",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isSensitive",
|
||||
"columnName": "isSensitive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isRemoteDevice",
|
||||
"columnName": "isRemoteDevice",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"_id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_clipboard_history__id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"_id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_clipboard_history__id` ON `${TABLE_NAME}` (`_id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '282a1b421e498fd0e21c055b6a4315e0')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -392,6 +392,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "tamil",
|
||||
"label": "Tamil",
|
||||
"authors": [ "Clem0908" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "thai_kedmanee",
|
||||
"label": "Thai Kedmanee",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"all": {
|
||||
"c": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 269, "label": "č" },
|
||||
{ "$": "auto_text_key", "code": 269, "label": "č" }
|
||||
]
|
||||
},
|
||||
"s": {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;grinsendes Gesicht;Gesicht|grinsendes Gesicht|lol|lustig
|
||||
😃;grinsendes Gesicht mit großen Augen;Gesicht|grinsendes Gesicht mit großen Augen|lächeln|lol|lustig
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;grinning face;face|grin|grinning face
|
||||
😃;grinning face with big eyes;face|grinning face with big eyes|mouth|open|smile
|
||||
@@ -3788,3 +3791,4 @@
|
||||
🏴;flag: England;flag|flag: England
|
||||
🏴;flag: Scotland;flag|flag: Scotland
|
||||
🏴;flag: Wales;flag|flag: Wales
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;cara sonriendo;cara|cara sonriendo|divertido|feliz|sonrisa
|
||||
😃;cara sonriendo con ojos grandes;cara|cara sonriendo con ojos grandes|divertido|risa|sonriendo
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;visage rieur;sourire|visage rieur
|
||||
😃;visage souriant avec de grands yeux;sourire|visage souriant avec de grands yeux
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;faccina con un gran sorriso;faccina|faccina che sogghigna|faccina con un gran sorriso|risata|sogghignare
|
||||
😃;faccina con un gran sorriso e occhi spalancati;faccina|faccina con un gran sorriso e occhi spalancati|faccina sorridente|risata|sorridere
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;rosto risonho;lol|rindo|risada|rosto|rosto risonho
|
||||
😃;rosto risonho com olhos bem abertos;aberto|boca|rosto|rosto risonho com olhos bem abertos|sorriso
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Auto-generated by emojicon.py using CLDR v45
|
||||
# DO NOT EDIT MANUALLY!
|
||||
|
||||
[smileys_emotion]
|
||||
😀;;
|
||||
😃;;
|
||||
@@ -3788,3 +3791,4 @@
|
||||
🏴;;
|
||||
🏴;;
|
||||
🏴;;
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@@ -87,6 +87,7 @@ import dev.patrickgold.florisboard.ime.keyboard.ProvideKeyboardRowBaseHeight
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
import dev.patrickgold.florisboard.ime.lifecycle.LifecycleInputMethodService
|
||||
import dev.patrickgold.florisboard.ime.media.MediaInputLayout
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedPanel
|
||||
import dev.patrickgold.florisboard.ime.sheet.BottomSheetHostUi
|
||||
@@ -370,7 +371,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
flogInfo { "(no args)" }
|
||||
super.onFinishInput()
|
||||
editorInstance.handleFinishInput()
|
||||
nlpManager.clearInlineSuggestions()
|
||||
NlpInlineAutofill.clearInlineSuggestions()
|
||||
}
|
||||
|
||||
override fun onWindowShown() {
|
||||
@@ -437,23 +438,26 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
override fun onCreateInlineSuggestionsRequest(uiExtras: Bundle): InlineSuggestionsRequest? {
|
||||
return if (prefs.smartbar.enabled.get() && prefs.suggestion.api30InlineSuggestionsEnabled.get()) {
|
||||
flogInfo(LogTopic.IMS_EVENTS) {
|
||||
"Creating inline suggestions request because Smartbar and inline suggestions are enabled."
|
||||
}
|
||||
val stylesBundle = themeManager.createInlineSuggestionUiStyleBundle(this)
|
||||
val spec = InlinePresentationSpec.Builder(InlineSuggestionUiSmallestSize, InlineSuggestionUiBiggestSize)
|
||||
.setStyle(stylesBundle)
|
||||
.build()
|
||||
InlineSuggestionsRequest.Builder(listOf(spec)).let { request ->
|
||||
request.setMaxSuggestionCount(InlineSuggestionsRequest.SUGGESTION_COUNT_UNLIMITED)
|
||||
request.build()
|
||||
}
|
||||
} else {
|
||||
if (!prefs.smartbar.enabled.get() || !prefs.suggestion.api30InlineSuggestionsEnabled.get()) {
|
||||
flogInfo(LogTopic.IMS_EVENTS) {
|
||||
"Ignoring inline suggestions request because Smartbar and/or inline suggestions are disabled."
|
||||
}
|
||||
null
|
||||
return null
|
||||
}
|
||||
|
||||
flogInfo(LogTopic.IMS_EVENTS) { "Creating inline suggestions request" }
|
||||
val stylesBundle = themeManager.createInlineSuggestionUiStyleBundle(this)
|
||||
val spec = InlinePresentationSpec.Builder(
|
||||
InlineSuggestionUiSmallestSize,
|
||||
InlineSuggestionUiBiggestSize,
|
||||
).run {
|
||||
setStyle(stylesBundle)
|
||||
build()
|
||||
}
|
||||
|
||||
return InlineSuggestionsRequest.Builder(listOf(spec)).run {
|
||||
setMaxSuggestionCount(InlineSuggestionsRequest.SUGGESTION_COUNT_UNLIMITED)
|
||||
build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,8 +467,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
flogInfo(LogTopic.IMS_EVENTS) {
|
||||
"Received inline suggestions response with ${inlineSuggestions.size} suggestion(s) provided."
|
||||
}
|
||||
nlpManager.showInlineSuggestions(inlineSuggestions)
|
||||
return true
|
||||
return NlpInlineAutofill.showInlineSuggestions(this, inlineSuggestions)
|
||||
}
|
||||
|
||||
override fun onComputeInsets(outInsets: Insets?) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Patrick Goldinger
|
||||
* Copyright (C) 2021-2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,8 +31,9 @@ import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
|
||||
import dev.patrickgold.florisboard.ime.keyboard.SpaceBarMode
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHairStyle
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiRecentlyUsedHelper
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHistory
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSuggestionType
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.smartbar.CandidatesDisplayMode
|
||||
@@ -56,6 +57,8 @@ import dev.patrickgold.jetpref.datastore.model.PreferenceMigrationEntry
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceModel
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceType
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
fun florisPreferenceModel() = JetPref.getOrCreatePreferenceModel(AppPrefs::class, ::AppPrefs)
|
||||
|
||||
@@ -171,6 +174,10 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
key = "devtools__show_spelling_overlay",
|
||||
default = false,
|
||||
)
|
||||
val showInlineAutofillOverlay = boolean(
|
||||
key = "devtools__show_inline_autofill_overlay",
|
||||
default = false,
|
||||
)
|
||||
val showKeyTouchBoundaries = boolean(
|
||||
key = "devtools__show_touch_boundaries",
|
||||
default = false,
|
||||
@@ -193,6 +200,67 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
)
|
||||
}
|
||||
|
||||
val emoji = Emoji()
|
||||
inner class Emoji {
|
||||
val preferredSkinTone = enum(
|
||||
key = "emoji__preferred_skin_tone",
|
||||
default = EmojiSkinTone.DEFAULT,
|
||||
)
|
||||
val preferredHairStyle = enum(
|
||||
key = "emoji__preferred_hair_style",
|
||||
default = EmojiHairStyle.DEFAULT,
|
||||
)
|
||||
val historyEnabled = boolean(
|
||||
key = "emoji__history_enabled",
|
||||
default = true,
|
||||
)
|
||||
val historyData = custom(
|
||||
key = "emoji__history_data",
|
||||
default = EmojiHistory.Empty,
|
||||
serializer = EmojiHistory.Serializer,
|
||||
)
|
||||
val historyPinnedUpdateStrategy = enum(
|
||||
key = "emoji__history_pinned_update_strategy",
|
||||
default = EmojiHistory.UpdateStrategy.MANUAL_SORT_PREPEND,
|
||||
)
|
||||
val historyPinnedMaxSize = int(
|
||||
key = "emoji__history_pinned_max_size",
|
||||
default = EmojiHistory.MaxSizeUnlimited,
|
||||
)
|
||||
val historyRecentUpdateStrategy = enum(
|
||||
key = "emoji__history_recent_update_strategy",
|
||||
default = EmojiHistory.UpdateStrategy.AUTO_SORT_PREPEND,
|
||||
)
|
||||
val historyRecentMaxSize = int(
|
||||
key = "emoji__history_recent_max_size",
|
||||
default = 90,
|
||||
)
|
||||
val suggestionEnabled = boolean(
|
||||
key = "emoji__suggestion_enabled",
|
||||
default = true,
|
||||
)
|
||||
val suggestionType = enum(
|
||||
key = "emoji__suggestion_type",
|
||||
default = EmojiSuggestionType.LEADING_COLON,
|
||||
)
|
||||
val suggestionUpdateHistory = boolean(
|
||||
key = "emoji__suggestion_update_history",
|
||||
default = true,
|
||||
)
|
||||
val suggestionCandidateShowName = boolean(
|
||||
key = "emoji__suggestion_candidate_show_name",
|
||||
default = false,
|
||||
)
|
||||
val suggestionQueryMinLength = int(
|
||||
key = "emoji__suggestion_query_min_length",
|
||||
default = 3,
|
||||
)
|
||||
val suggestionCandidateMaxCount = int(
|
||||
key = "emoji__suggestion_candidate_max_count",
|
||||
default = 5,
|
||||
)
|
||||
}
|
||||
|
||||
val gestures = Gestures()
|
||||
inner class Gestures {
|
||||
val swipeUp = enum(
|
||||
@@ -530,27 +598,6 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
)
|
||||
}
|
||||
|
||||
val media = Media()
|
||||
inner class Media {
|
||||
val emojiRecentlyUsed = custom(
|
||||
key = "media__emoji_recently_used",
|
||||
default = emptyList(),
|
||||
serializer = EmojiRecentlyUsedHelper.Serializer,
|
||||
)
|
||||
val emojiRecentlyUsedMaxSize = int(
|
||||
key = "media__emoji_recently_used_max_size",
|
||||
default = 90,
|
||||
)
|
||||
val emojiPreferredSkinTone = enum(
|
||||
key = "media__emoji_preferred_skin_tone",
|
||||
default = EmojiSkinTone.DEFAULT,
|
||||
)
|
||||
val emojiPreferredHairStyle = enum(
|
||||
key = "media__emoji_preferred_hair_style",
|
||||
default = EmojiHairStyle.DEFAULT,
|
||||
)
|
||||
}
|
||||
|
||||
val smartbar = Smartbar()
|
||||
inner class Smartbar {
|
||||
val enabled = boolean(
|
||||
@@ -574,6 +621,7 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
key = "smartbar__shared_actions_expanded",
|
||||
default = false,
|
||||
)
|
||||
@Deprecated("Always enabled due to UX issues")
|
||||
val sharedActionsAutoExpandCollapse = boolean(
|
||||
key = "smartbar__shared_actions_auto_expand_collapse",
|
||||
default = true,
|
||||
@@ -683,8 +731,7 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
"gestures__space_bar_swipe_right", "gestures__space_bar_long_press", "gestures__delete_key_swipe_left",
|
||||
"gestures__delete_key_long_press", "keyboard__hinted_number_row_mode", "keyboard__hinted_symbols_mode",
|
||||
"keyboard__utility_key_action", "keyboard__one_handed_mode", "keyboard__landscape_input_ui_mode",
|
||||
"localization__display_language_names_in", "media__emoji_preferred_skin_tone",
|
||||
"media__emoji_preferred_hair_style", "smartbar__primary_actions_row_type",
|
||||
"localization__display_language_names_in", "smartbar__primary_actions_row_type",
|
||||
"smartbar__secondary_actions_placement", "smartbar__secondary_actions_row_type", "spelling__language_mode",
|
||||
"suggestion__display_mode", "theme__mode", "theme__editor_display_colors_as",
|
||||
"theme__editor_display_kbd_after_dialogs", "theme__editor_level",
|
||||
@@ -706,6 +753,32 @@ class AppPrefs : PreferenceModel("florisboard-app-prefs") {
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate media prefs to emoji prefs
|
||||
// Keep migration rule until: 0.6 dev cycle
|
||||
"media__emoji_recently_used" -> {
|
||||
val emojiValues = entry.rawValue.split(";")
|
||||
val recent = emojiValues.map {
|
||||
dev.patrickgold.florisboard.ime.media.emoji.Emoji(it, "", emptyList())
|
||||
}
|
||||
val data = EmojiHistory(emptyList(), recent)
|
||||
entry.transform(key = "emoji__history_data", rawValue = Json.encodeToString(data))
|
||||
}
|
||||
"media__emoji_recently_used_max_size" -> {
|
||||
entry.transform(key = "emoji__history_recent_max_size")
|
||||
}
|
||||
"media__emoji_preferred_skin_tone" -> {
|
||||
entry.transform(
|
||||
key = "emoji__preferred_skin_tone",
|
||||
rawValue = entry.rawValue.uppercase(), // keep until: 0.5 dev cycle
|
||||
)
|
||||
}
|
||||
"media__emoji_preferred_hair_style" -> {
|
||||
entry.transform(
|
||||
key = "emoji__preferred_hair_style",
|
||||
rawValue = entry.rawValue.uppercase(), // keep until: 0.5 dev cycle
|
||||
)
|
||||
}
|
||||
|
||||
// Default: keep entry
|
||||
else -> entry.keepAsIs()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ import dev.patrickgold.florisboard.ime.input.InputFeedbackActivationMode
|
||||
import dev.patrickgold.florisboard.ime.keyboard.IncognitoMode
|
||||
import dev.patrickgold.florisboard.ime.keyboard.SpaceBarMode
|
||||
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHistory
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSuggestionType
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingLanguageMode
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.smartbar.CandidatesDisplayMode
|
||||
@@ -138,6 +140,30 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
|
||||
)
|
||||
}
|
||||
},
|
||||
EmojiHistory.UpdateStrategy::class to DEFAULT to {
|
||||
listPrefEntries {
|
||||
entry(
|
||||
key = EmojiHistory.UpdateStrategy.AUTO_SORT_PREPEND,
|
||||
label = stringRes(R.string.enum__emoji_history_update_strategy__auto_sort_prepend),
|
||||
description = stringRes(R.string.enum__emoji_history_update_strategy__auto_sort_prepend__description),
|
||||
)
|
||||
entry(
|
||||
key = EmojiHistory.UpdateStrategy.AUTO_SORT_APPEND,
|
||||
label = stringRes(R.string.enum__emoji_history_update_strategy__auto_sort_append),
|
||||
description = stringRes(R.string.enum__emoji_history_update_strategy__auto_sort_append__description),
|
||||
)
|
||||
entry(
|
||||
key = EmojiHistory.UpdateStrategy.MANUAL_SORT_PREPEND,
|
||||
label = stringRes(R.string.enum__emoji_history_update_strategy__manual_sort_prepend),
|
||||
description = stringRes(R.string.enum__emoji_history_update_strategy__manual_sort_prepend__description),
|
||||
)
|
||||
entry(
|
||||
key = EmojiHistory.UpdateStrategy.MANUAL_SORT_APPEND,
|
||||
label = stringRes(R.string.enum__emoji_history_update_strategy__manual_sort_append),
|
||||
description = stringRes(R.string.enum__emoji_history_update_strategy__manual_sort_append__description),
|
||||
)
|
||||
}
|
||||
},
|
||||
EmojiSkinTone::class to DEFAULT to {
|
||||
listPrefEntries {
|
||||
entry(
|
||||
@@ -184,6 +210,20 @@ private val ENUM_DISPLAY_ENTRIES = mapOf<Pair<KClass<*>, String>, @Composable ()
|
||||
)
|
||||
}
|
||||
},
|
||||
EmojiSuggestionType::class to DEFAULT to {
|
||||
listPrefEntries {
|
||||
entry(
|
||||
key = EmojiSuggestionType.LEADING_COLON,
|
||||
label = stringRes(R.string.enum__emoji_suggestion_type__leading_colon),
|
||||
description = stringRes(R.string.enum__emoji_suggestion_type__leading_colon__description),
|
||||
)
|
||||
entry(
|
||||
key = EmojiSuggestionType.INLINE_TEXT,
|
||||
label = stringRes(R.string.enum__emoji_suggestion_type__inline_text),
|
||||
description = stringRes(R.string.enum__emoji_suggestion_type__inline_text__description),
|
||||
)
|
||||
}
|
||||
},
|
||||
ExtendedActionsPlacement::class to DEFAULT to {
|
||||
listPrefEntries {
|
||||
entry(
|
||||
|
||||
@@ -144,19 +144,19 @@ class FlorisAppActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
setIntent(intent)
|
||||
|
||||
if (intent?.action == Intent.ACTION_VIEW && intent.categories?.contains(Intent.CATEGORY_BROWSABLE) == true) {
|
||||
if (intent.action == Intent.ACTION_VIEW && intent.categories?.contains(Intent.CATEGORY_BROWSABLE) == true) {
|
||||
intentToBeHandled = intent
|
||||
return
|
||||
}
|
||||
if (intent?.action == Intent.ACTION_VIEW && intent.data != null) {
|
||||
if (intent.action == Intent.ACTION_VIEW && intent.data != null) {
|
||||
intentToBeHandled = intent
|
||||
return
|
||||
}
|
||||
if (intent?.action == Intent.ACTION_SEND && intent.clipData != null) {
|
||||
if (intent.action == Intent.ACTION_SEND && intent.clipData != null) {
|
||||
intentToBeHandled = intent
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.devtools
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
@@ -40,10 +42,12 @@ import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import dev.patrickgold.florisboard.editorInstance
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@@ -57,6 +61,7 @@ fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
val showPrimaryClip by prefs.devtools.showPrimaryClip.observeAsState()
|
||||
val showInputStateOverlay by prefs.devtools.showInputStateOverlay.observeAsState()
|
||||
val showSpellingOverlay by prefs.devtools.showSpellingOverlay.observeAsState()
|
||||
val showInlineAutofillOverlay by prefs.devtools.showInlineAutofillOverlay.observeAsState()
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides Color.White,
|
||||
@@ -72,6 +77,9 @@ fun DevtoolsOverlay(modifier: Modifier = Modifier) {
|
||||
if (showSpellingOverlay) {
|
||||
DevtoolsSpellingOverlay()
|
||||
}
|
||||
if (showInlineAutofillOverlay && AndroidVersion.ATLEAST_API30_R) {
|
||||
DevtoolsInlineAutofillOverlay()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,7 +125,6 @@ private fun DevtoolsInputStateOverlay() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsSpellingOverlay() {
|
||||
val context = LocalContext.current
|
||||
@@ -160,6 +167,25 @@ private fun DevtoolsSpellingOverlay() {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@Composable
|
||||
private fun DevtoolsInlineAutofillOverlay() {
|
||||
val inlineSuggestions by NlpInlineAutofill.suggestions.collectAsState()
|
||||
|
||||
DevtoolsOverlayBox(title = "Inline autofill overlay (${inlineSuggestions.size})") {
|
||||
for (inlineSuggestion in inlineSuggestions) {
|
||||
DevtoolsSubGroup(title = "NlpInlineSuggestion") {
|
||||
val info = inlineSuggestion.info
|
||||
DevtoolsText(text = "info.type: ${info.type}")
|
||||
DevtoolsText(text = "info.source: ${info.source}")
|
||||
DevtoolsText(text = "info.isPinned: ${info.isPinned}")
|
||||
val view = inlineSuggestion.view
|
||||
DevtoolsText(text = "view: ${view?.javaClass?.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DevtoolsOverlayBox(
|
||||
title: String,
|
||||
|
||||
@@ -36,6 +36,7 @@ import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
|
||||
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
|
||||
class DebugOnPurposeCrashException : Exception(
|
||||
"Success! The app crashed purposely to display this beautiful screen we all love :)"
|
||||
@@ -84,6 +85,13 @@ fun DevtoolsScreen() = FlorisScreen {
|
||||
summary = stringRes(R.string.devtools__show_spelling_overlay__summary),
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.devtools.showInlineAutofillOverlay,
|
||||
title = stringRes(R.string.devtools__show_inline_autofill_overlay__label),
|
||||
summary = stringRes(R.string.devtools__show_inline_autofill_overlay__summary),
|
||||
enabledIf = { prefs.devtools.enabled isEqualTo true },
|
||||
visibleIf = { AndroidVersion.ATLEAST_API30_R },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.devtools.showKeyTouchBoundaries,
|
||||
title = stringRes(R.string.devtools__show_key_touch_boundaries__label),
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.devtools
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -35,19 +37,21 @@ import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.sp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisButton
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.devtools.Devtools
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
|
||||
// TODO: This screen is just a quick thrown-together thing and needs further enhancing in the UI and in localization
|
||||
// TODO: This screen is just a quick thrown-together thing and needs further enhancing in the UI
|
||||
@Composable
|
||||
fun ExportDebugLogScreen() = FlorisScreen {
|
||||
title = "Debug log"
|
||||
title = stringRes(R.string.devtools__debuglog__title)
|
||||
scrollable = false
|
||||
|
||||
val prefs by florisPreferenceModel()
|
||||
@@ -55,21 +59,36 @@ fun ExportDebugLogScreen() = FlorisScreen {
|
||||
val clipboardManager by context.clipboardManager()
|
||||
|
||||
var debugLog by remember { mutableStateOf<List<String>?>(null) }
|
||||
var formattedDebugLog by remember { mutableStateOf<List<String>?>(null) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
debugLog = Devtools.generateDebugLog(context, prefs, includeLogcat = true).lines()
|
||||
formattedDebugLog = Devtools.generateDebugLogForGithub(context, prefs, includeLogcat = true).lines()
|
||||
}
|
||||
|
||||
bottomBar {
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
clipboardManager.addNewPlaintext(debugLog!!.joinToString("\n"))
|
||||
context.showShortToast("Copied debug log to clipboard")
|
||||
},
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = "Export (copy to clipboard)",
|
||||
enabled = debugLog != null,
|
||||
)
|
||||
) {
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
clipboardManager.addNewPlaintext(debugLog!!.joinToString("\n"))
|
||||
context.showShortToast(context.getString(R.string.devtools__debuglog__copied_to_clipboard))
|
||||
},
|
||||
modifier = Modifier,
|
||||
text = stringRes(R.string.devtools__debuglog__copy_log),
|
||||
enabled = debugLog != null,
|
||||
)
|
||||
FlorisButton(
|
||||
onClick = {
|
||||
clipboardManager.addNewPlaintext(formattedDebugLog!!.joinToString("\n"))
|
||||
context.showShortToast(context.getString(R.string.devtools__debuglog__copied_to_clipboard))
|
||||
},
|
||||
text = stringRes(R.string.devtools__debuglog__copy_for_github),
|
||||
enabled = debugLog != null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
content {
|
||||
@@ -86,7 +105,7 @@ fun ExportDebugLogScreen() = FlorisScreen {
|
||||
val log = debugLog
|
||||
if (log == null) {
|
||||
item {
|
||||
Text("Loading...")
|
||||
Text(stringRes(R.string.devtools__debuglog__loading))
|
||||
}
|
||||
} else {
|
||||
items(log) { logLine ->
|
||||
|
||||
@@ -30,9 +30,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.outlined.LibraryBooks
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Code
|
||||
import androidx.compose.material.icons.outlined.LibraryBooks
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
@@ -322,17 +322,17 @@ private fun EditScreen(
|
||||
FlorisOutlinedBox(
|
||||
modifier = Modifier.defaultFlorisOutlinedBox(),
|
||||
) {
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
onClick = { workspace.currentAction = EditorAction.ManageMetaData },
|
||||
icon = Icons.Default.Code,
|
||||
title = stringRes(R.string.ext__editor__metadata__title),
|
||||
)
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
onClick = { workspace.currentAction = EditorAction.ManageDependencies },
|
||||
icon = Icons.Outlined.LibraryBooks,
|
||||
icon = Icons.AutoMirrored.Outlined.LibraryBooks,
|
||||
title = stringRes(R.string.ext__editor__dependencies__title),
|
||||
)
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
onClick = { workspace.currentAction = EditorAction.ManageFiles },
|
||||
icon = vectorResource(R.drawable.ic_file_blank),
|
||||
title = stringRes(R.string.ext__editor__files__title),
|
||||
|
||||
@@ -31,7 +31,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Share
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -224,7 +224,7 @@ private fun ExtensionMetaRowSimpleText(
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
if (showDividerAbove) {
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
Row(
|
||||
modifier = modifier
|
||||
@@ -246,7 +246,7 @@ private fun ExtensionMetaRowScrollableChips(
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
if (showDividerAbove) {
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
}
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
|
||||
@@ -25,13 +25,17 @@ import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.TriStateCheckbox
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.state.ToggleableState
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.core.content.FileProvider
|
||||
@@ -86,10 +90,23 @@ object Backup {
|
||||
var clipboardTextItems by mutableStateOf(false)
|
||||
var clipboardImageItems by mutableStateOf(false)
|
||||
var clipboardVideoItems by mutableStateOf(false)
|
||||
var clipboardData by mutableStateOf(false)
|
||||
|
||||
fun validateClipboardCheckbox(): Boolean {
|
||||
return clipboardTextItems && clipboardImageItems && clipboardVideoItems
|
||||
private var _clipboardData: MutableState<ToggleableState> = mutableStateOf(ToggleableState.Off)
|
||||
val clipboardData: State<ToggleableState> = _clipboardData
|
||||
|
||||
fun updateCheckboxState() {
|
||||
val newValue = if (
|
||||
!clipboardVideoItems && !clipboardImageItems && !clipboardTextItems
|
||||
) {
|
||||
ToggleableState.Off
|
||||
} else if (
|
||||
clipboardVideoItems && clipboardImageItems && clipboardTextItems
|
||||
) {
|
||||
ToggleableState.On
|
||||
} else {
|
||||
ToggleableState.Indeterminate
|
||||
}
|
||||
_clipboardData.value = newValue
|
||||
}
|
||||
|
||||
fun provideClipboardItems(): Boolean {
|
||||
@@ -309,28 +326,31 @@ internal fun BackupFilesSelector(
|
||||
text = stringRes(R.string.backup_and_restore__back_up__files_ime_theme),
|
||||
)
|
||||
|
||||
CheckboxListItem(
|
||||
TriStateCheckboxListItem(
|
||||
onClick = {
|
||||
if (!filesSelector.clipboardData) {
|
||||
filesSelector.clipboardTextItems = true
|
||||
if (
|
||||
filesSelector.clipboardData.value == ToggleableState.Off ||
|
||||
filesSelector.clipboardData.value == ToggleableState.Indeterminate
|
||||
) {
|
||||
filesSelector.clipboardImageItems = true
|
||||
filesSelector.clipboardVideoItems = true
|
||||
filesSelector.clipboardTextItems = true
|
||||
} else {
|
||||
filesSelector.clipboardTextItems = false
|
||||
filesSelector.clipboardImageItems = false
|
||||
filesSelector.clipboardVideoItems = false
|
||||
filesSelector.clipboardTextItems = false
|
||||
}
|
||||
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
|
||||
filesSelector.updateCheckboxState()
|
||||
},
|
||||
checked = filesSelector.clipboardTextItems && filesSelector.clipboardImageItems && filesSelector.clipboardVideoItems,
|
||||
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history)
|
||||
state = filesSelector.clipboardData.value,
|
||||
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history),
|
||||
)
|
||||
|
||||
|
||||
CheckboxListItem(
|
||||
onClick = {
|
||||
filesSelector.clipboardTextItems = !filesSelector.clipboardTextItems
|
||||
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
|
||||
filesSelector.updateCheckboxState()
|
||||
},
|
||||
checked = filesSelector.clipboardTextItems,
|
||||
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history__clipboard_text_items),
|
||||
@@ -339,7 +359,7 @@ internal fun BackupFilesSelector(
|
||||
CheckboxListItem(
|
||||
onClick = {
|
||||
filesSelector.clipboardImageItems = !filesSelector.clipboardImageItems
|
||||
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
|
||||
filesSelector.updateCheckboxState()
|
||||
},
|
||||
checked = filesSelector.clipboardImageItems,
|
||||
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history__clipboard_image_items),
|
||||
@@ -348,7 +368,7 @@ internal fun BackupFilesSelector(
|
||||
CheckboxListItem(
|
||||
onClick = {
|
||||
filesSelector.clipboardVideoItems = !filesSelector.clipboardVideoItems
|
||||
filesSelector.clipboardData = filesSelector.validateClipboardCheckbox()
|
||||
filesSelector.updateCheckboxState()
|
||||
},
|
||||
checked = filesSelector.clipboardVideoItems,
|
||||
text = stringRes(R.string.backup_and_restore__back_up__files_clipboard_history__clipboard_video_items),
|
||||
@@ -382,6 +402,30 @@ internal fun CheckboxListItem(
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TriStateCheckboxListItem(
|
||||
onClick: () -> Unit,
|
||||
state: ToggleableState,
|
||||
text: String,
|
||||
isSecondaryListItem: Boolean = false,
|
||||
) {
|
||||
JetPrefListItem(
|
||||
modifier = Modifier.rippleClickable(onClick = onClick),
|
||||
icon = {
|
||||
Row {
|
||||
if (isSecondaryListItem) {
|
||||
Spacer(modifier = Modifier.width(40.dp))
|
||||
}
|
||||
TriStateCheckbox(
|
||||
state = state,
|
||||
onClick = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
text = text,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun RadioListItem(
|
||||
onClick: () -> Unit,
|
||||
|
||||
@@ -138,7 +138,10 @@ fun RestoreScreen() = FlorisScreen {
|
||||
}
|
||||
restoreWorkspace = workspace
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(R.string.backup_and_restore__restore__failure, "error_message" to error.localizedMessage)
|
||||
context.showLongToast(
|
||||
R.string.backup_and_restore__restore__failure,
|
||||
"error_message" to error.localizedMessage,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -176,15 +179,20 @@ fun RestoreScreen() = FlorisScreen {
|
||||
srcDir.copyRecursively(dstDir, overwrite = true)
|
||||
}
|
||||
}
|
||||
val clipboardManager = context.clipboardManager().value
|
||||
if (shouldReset) {
|
||||
clipboardManager.clearFullHistory()
|
||||
ClipboardFileStorage.resetClipboardFileStorage(context)
|
||||
}
|
||||
|
||||
if (restoreFilesSelector.provideClipboardItems()) {
|
||||
val clipboardFilesDir = workspace.outputDir.subDir("clipboard")
|
||||
val clipboardManager = context.clipboardManager().value
|
||||
|
||||
if (restoreFilesSelector.clipboardTextItems) {
|
||||
val clipboardItems = clipboardFilesDir.subFile(Backup.CLIPBOARD_TEXT_ITEMS_JSON_NAME)
|
||||
if (clipboardItems.exists()) {
|
||||
val clipboardItemsList = clipboardItems.readJson<List<ClipboardItem>>()
|
||||
clipboardManager.restoreHistory(shouldReset = shouldReset, items = clipboardItemsList.filter { it.type == ItemType.TEXT }, itemType = ItemType.TEXT)
|
||||
clipboardManager.restoreHistory(items = clipboardItemsList.filter { it.type == ItemType.TEXT })
|
||||
}
|
||||
}
|
||||
if (restoreFilesSelector.clipboardImageItems) {
|
||||
@@ -192,14 +200,18 @@ fun RestoreScreen() = FlorisScreen {
|
||||
if (clipboardItems.exists()) {
|
||||
val clipboardItemsList = clipboardItems.readJson<List<ClipboardItem>>()
|
||||
for (item in clipboardItemsList.filter { it.type == ItemType.IMAGE }) {
|
||||
ClipboardFileStorage.instertFileFromBackup(
|
||||
ClipboardFileStorage.insertFileFromBackupIfNotExisting(
|
||||
context,
|
||||
clipboardFilesDir.subFile(
|
||||
relPath = "${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/${item.uri!!.path!!.split('/').last()}"
|
||||
relPath = "${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/${
|
||||
item.uri!!.path!!.split(
|
||||
'/'
|
||||
).last()
|
||||
}"
|
||||
)
|
||||
)
|
||||
}
|
||||
clipboardManager.restoreHistory(shouldReset = shouldReset, items = clipboardItemsList.filter { it.type == ItemType.IMAGE }, itemType = ItemType.IMAGE)
|
||||
clipboardManager.restoreHistory(items = clipboardItemsList.filter { it.type == ItemType.IMAGE })
|
||||
}
|
||||
}
|
||||
if (restoreFilesSelector.clipboardVideoItems) {
|
||||
@@ -207,14 +219,18 @@ fun RestoreScreen() = FlorisScreen {
|
||||
if (clipboardItems.exists()) {
|
||||
val clipboardItemsList = clipboardItems.readJson<List<ClipboardItem>>()
|
||||
for (item in clipboardItemsList.filter { it.type == ItemType.VIDEO }) {
|
||||
ClipboardFileStorage.instertFileFromBackup(
|
||||
ClipboardFileStorage.insertFileFromBackupIfNotExisting(
|
||||
context,
|
||||
clipboardFilesDir.subFile(
|
||||
relPath = "${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/${item.uri!!.path!!.split('/').last()}"
|
||||
relPath = "${ClipboardFileStorage.CLIPBOARD_FILES_PATH}/${
|
||||
item.uri!!.path!!.split(
|
||||
'/'
|
||||
).last()
|
||||
}"
|
||||
)
|
||||
)
|
||||
}
|
||||
clipboardManager.restoreHistory(shouldReset = shouldReset, items = clipboardItemsList.filter { it.type == ItemType.VIDEO }, itemType = ItemType.VIDEO)
|
||||
clipboardManager.restoreHistory(items = clipboardItemsList.filter { it.type == ItemType.VIDEO })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +254,11 @@ fun RestoreScreen() = FlorisScreen {
|
||||
context.showLongToast(R.string.backup_and_restore__restore__success)
|
||||
navController.navigateUp()
|
||||
} catch (e: Throwable) {
|
||||
context.showLongToast(R.string.backup_and_restore__restore__failure, "error_message" to e.localizedMessage)
|
||||
e.printStackTrace()
|
||||
context.showLongToast(
|
||||
R.string.backup_and_restore__restore__failure,
|
||||
"error_message" to e.localizedMessage,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -273,7 +293,10 @@ fun RestoreScreen() = FlorisScreen {
|
||||
runCatching {
|
||||
restoreDataFromFileSystemLauncher.launch("*/*")
|
||||
}.onFailure { error ->
|
||||
context.showLongToast(R.string.backup_and_restore__restore__failure, "error_message" to error.localizedMessage)
|
||||
context.showLongToast(
|
||||
R.string.backup_and_restore__restore__failure,
|
||||
"error_message" to error.localizedMessage,
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
@@ -295,15 +318,15 @@ fun RestoreScreen() = FlorisScreen {
|
||||
modifier = Modifier.defaultFlorisOutlinedBox(),
|
||||
title = stringRes(R.string.backup_and_restore__restore__metadata),
|
||||
) {
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
icon = Icons.Default.Code,
|
||||
title = workspace.metadata.packageName,
|
||||
)
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
icon = Icons.Outlined.Info,
|
||||
title = "${workspace.metadata.versionName} (${workspace.metadata.versionCode})",
|
||||
)
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
icon = Icons.Default.Schedule,
|
||||
title = remember(workspace.metadata.timestamp) {
|
||||
val formatter = DateFormat.getDateTimeInstance()
|
||||
|
||||
@@ -24,8 +24,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
@@ -193,7 +193,7 @@ fun UserDictionaryScreen(type: UserDictionaryType) = FlorisScreen {
|
||||
icon = if (currentLocale != null) {
|
||||
Icons.Default.Close
|
||||
} else {
|
||||
Icons.Default.ArrowBack
|
||||
Icons.AutoMirrored.Filled.ArrowBack
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ fun LanguagePackManagerScreen(action: LanguagePackManagerScreenAction?) = Floris
|
||||
FlorisOutlinedBox(
|
||||
modifier = Modifier.defaultFlorisOutlinedBox(),
|
||||
) {
|
||||
this@content.Preference(
|
||||
Preference(
|
||||
onClick = { navController.navigate(
|
||||
Routes.Ext.Import(ExtensionImportScreenType.EXT_LANGUAGEPACK, null)
|
||||
) },
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.settings.localization
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
@@ -24,8 +26,13 @@ import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.Saver
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -33,8 +40,8 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.cacheManager
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.keyboard.LayoutType
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
@@ -46,7 +53,20 @@ import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.Preference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
|
||||
import dev.patrickgold.jetpref.material.ui.JetPrefAlertDialog
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
internal val SubtypeSaver = Saver<MutableState<Subtype?>, String>(
|
||||
save = {
|
||||
Json.encodeToString<Subtype?>(it.value)
|
||||
},
|
||||
restore = {
|
||||
mutableStateOf(Json.decodeFromString(it))
|
||||
},
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun LocalizationScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.settings__localization__title)
|
||||
@@ -57,7 +77,7 @@ fun LocalizationScreen() = FlorisScreen {
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val subtypeManager by context.subtypeManager()
|
||||
val cacheManager by context.cacheManager()
|
||||
var chosenSubtypeToDelete: Subtype? by rememberSaveable(saver = SubtypeSaver) { mutableStateOf(null) }
|
||||
|
||||
floatingActionButton {
|
||||
ExtendedFloatingActionButton(
|
||||
@@ -84,7 +104,6 @@ fun LocalizationScreen() = FlorisScreen {
|
||||
entries = enumDisplayEntriesOf(DisplayLanguageNamesIn::class),
|
||||
)
|
||||
Preference(
|
||||
// icon = R.drawable.ic_edit,
|
||||
title = stringRes(R.string.settings__localization__language_pack_title),
|
||||
summary = stringRes(R.string.settings__localization__language_pack_summary),
|
||||
onClick = {
|
||||
@@ -118,17 +137,50 @@ fun LocalizationScreen() = FlorisScreen {
|
||||
DisplayLanguageNamesIn.NATIVE_LOCALE -> subtype.primaryLocale.displayName(subtype.primaryLocale)
|
||||
},
|
||||
summary = summary,
|
||||
onClick = {
|
||||
navController.navigate(
|
||||
Routes.Settings.SubtypeEdit(subtype.id)
|
||||
)
|
||||
},
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {
|
||||
navController.navigate(
|
||||
Routes.Settings.SubtypeEdit(subtype.id)
|
||||
)
|
||||
},
|
||||
onLongClick = {
|
||||
chosenSubtypeToDelete = subtype
|
||||
},
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//PreferenceGroup(title = stringRes(R.string.settings__localization__group_layouts__label)) {
|
||||
//}
|
||||
DeleteSubtypeConfirmationDialog(
|
||||
subtypeToDelete = chosenSubtypeToDelete,
|
||||
onDismiss = {
|
||||
chosenSubtypeToDelete = null
|
||||
},
|
||||
onConfirm = {
|
||||
chosenSubtypeToDelete?.let { subtypeManager.removeSubtype(subtypeToRemove = it) }
|
||||
chosenSubtypeToDelete = null
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DeleteSubtypeConfirmationDialog(
|
||||
subtypeToDelete: Subtype?,
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: () -> Unit,
|
||||
) {
|
||||
subtypeToDelete?.let {
|
||||
JetPrefAlertDialog(
|
||||
title = stringRes(R.string.settings__localization__subtype_delete_confirmation_title),
|
||||
confirmLabel = stringRes(R.string.action__yes),
|
||||
dismissLabel = stringRes(R.string.action__no),
|
||||
onDismiss = onDismiss,
|
||||
onConfirm = onConfirm,
|
||||
) {
|
||||
Text(stringRes(R.string.settings__localization__subtype_delete_confirmation_warning))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.LocalNavController
|
||||
import dev.patrickgold.florisboard.app.Routes
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,43 +16,126 @@
|
||||
|
||||
package dev.patrickgold.florisboard.app.settings.media
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.EmojiSymbols
|
||||
import androidx.compose.material.icons.outlined.Schedule
|
||||
import androidx.compose.runtime.Composable
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiHistory
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSkinTone
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSuggestionType
|
||||
import dev.patrickgold.florisboard.lib.compose.FlorisScreen
|
||||
import dev.patrickgold.florisboard.lib.compose.pluralsRes
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.ui.DialogSliderPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.ExperimentalJetPrefDatastoreUi
|
||||
import dev.patrickgold.jetpref.datastore.ui.ListPreference
|
||||
import dev.patrickgold.jetpref.datastore.ui.PreferenceGroup
|
||||
import dev.patrickgold.jetpref.datastore.ui.SwitchPreference
|
||||
|
||||
@OptIn(ExperimentalJetPrefDatastoreUi::class)
|
||||
@Composable
|
||||
fun MediaScreen() = FlorisScreen {
|
||||
title = stringRes(R.string.settings__media__title)
|
||||
previewFieldVisible = true
|
||||
iconSpaceReserved = false
|
||||
iconSpaceReserved = true
|
||||
|
||||
content {
|
||||
ListPreference(
|
||||
prefs.media.emojiPreferredSkinTone,
|
||||
prefs.emoji.preferredSkinTone,
|
||||
title = stringRes(R.string.prefs__media__emoji_preferred_skin_tone),
|
||||
entries = enumDisplayEntriesOf(EmojiSkinTone::class),
|
||||
)
|
||||
DialogSliderPreference(
|
||||
prefs.media.emojiRecentlyUsedMaxSize,
|
||||
title = stringRes(R.string.prefs__media__emoji_recently_used_max_size),
|
||||
valueLabel = { maxSize ->
|
||||
if (maxSize == 0) {
|
||||
stringRes(R.string.general__unlimited)
|
||||
} else {
|
||||
pluralsRes(R.plurals.unit__items__written, maxSize, "v" to maxSize)
|
||||
}
|
||||
},
|
||||
min = 0,
|
||||
max = 120,
|
||||
stepIncrement = 1,
|
||||
)
|
||||
|
||||
PreferenceGroup(title = stringRes(R.string.prefs__media__emoji_history__title)) {
|
||||
SwitchPreference(
|
||||
prefs.emoji.historyEnabled,
|
||||
icon = Icons.Outlined.Schedule,
|
||||
title = stringRes(R.string.prefs__media__emoji_history_enabled),
|
||||
summary = stringRes(R.string.prefs__media__emoji_history_enabled__summary),
|
||||
)
|
||||
ListPreference(
|
||||
prefs.emoji.historyPinnedUpdateStrategy,
|
||||
title = stringRes(R.string.prefs__media__emoji_history_pinned_update_strategy),
|
||||
entries = enumDisplayEntriesOf(EmojiHistory.UpdateStrategy::class),
|
||||
enabledIf = { prefs.emoji.historyEnabled.isTrue() },
|
||||
)
|
||||
ListPreference(
|
||||
prefs.emoji.historyRecentUpdateStrategy,
|
||||
title = stringRes(R.string.prefs__media__emoji_history_recent_update_strategy),
|
||||
entries = enumDisplayEntriesOf(EmojiHistory.UpdateStrategy::class),
|
||||
enabledIf = { prefs.emoji.historyEnabled.isTrue() },
|
||||
)
|
||||
DialogSliderPreference(
|
||||
primaryPref = prefs.emoji.historyPinnedMaxSize,
|
||||
secondaryPref = prefs.emoji.historyRecentMaxSize,
|
||||
title = stringRes(R.string.prefs__media__emoji_history_max_size),
|
||||
primaryLabel = stringRes(R.string.emoji__history__pinned),
|
||||
secondaryLabel = stringRes(R.string.emoji__history__recent),
|
||||
valueLabel = { maxSize ->
|
||||
if (maxSize == EmojiHistory.MaxSizeUnlimited) {
|
||||
stringRes(R.string.general__unlimited)
|
||||
} else {
|
||||
pluralsRes(R.plurals.unit__items__written, maxSize, "v" to maxSize)
|
||||
}
|
||||
},
|
||||
min = 0,
|
||||
max = 120,
|
||||
stepIncrement = 1,
|
||||
enabledIf = { prefs.emoji.historyEnabled.isTrue() },
|
||||
)
|
||||
}
|
||||
|
||||
PreferenceGroup(title = stringRes(R.string.prefs__media__emoji_suggestion__title)) {
|
||||
SwitchPreference(
|
||||
prefs.emoji.suggestionEnabled,
|
||||
icon = Icons.Outlined.EmojiSymbols,
|
||||
title = stringRes(R.string.prefs__media__emoji_suggestion_enabled),
|
||||
summary = stringRes(R.string.prefs__media__emoji_suggestion_enabled__summary),
|
||||
)
|
||||
ListPreference(
|
||||
prefs.emoji.suggestionType,
|
||||
title = stringRes(R.string.prefs__media__emoji_suggestion_type),
|
||||
entries = enumDisplayEntriesOf(EmojiSuggestionType::class),
|
||||
enabledIf = { prefs.emoji.suggestionEnabled.isTrue() },
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.emoji.suggestionUpdateHistory,
|
||||
title = stringRes(R.string.prefs__media__emoji_suggestion_update_history),
|
||||
summary = stringRes(R.string.prefs__media__emoji_suggestion_update_history__summary),
|
||||
enabledIf = {
|
||||
prefs.emoji.suggestionEnabled.isTrue() && prefs.emoji.historyEnabled.isTrue()
|
||||
},
|
||||
)
|
||||
SwitchPreference(
|
||||
prefs.emoji.suggestionCandidateShowName,
|
||||
title = stringRes(R.string.prefs__media__emoji_suggestion_candidate_show_name),
|
||||
summary = stringRes(R.string.prefs__media__emoji_suggestion_candidate_show_name__summary),
|
||||
enabledIf = { prefs.emoji.suggestionEnabled.isTrue() },
|
||||
)
|
||||
DialogSliderPreference(
|
||||
prefs.emoji.suggestionQueryMinLength,
|
||||
title = stringRes(R.string.prefs__media__emoji_suggestion_query_min_length),
|
||||
valueLabel = { length ->
|
||||
pluralsRes(R.plurals.unit__characters__written, length, "v" to length)
|
||||
},
|
||||
min = 1,
|
||||
max = 5,
|
||||
stepIncrement = 1,
|
||||
enabledIf = { prefs.emoji.suggestionEnabled.isTrue() },
|
||||
)
|
||||
DialogSliderPreference(
|
||||
prefs.emoji.suggestionCandidateMaxCount,
|
||||
title = stringRes(R.string.prefs__media__emoji_suggestion_candidate_max_count),
|
||||
valueLabel = { count ->
|
||||
pluralsRes(R.plurals.unit__candidates__written, count, "v" to count)
|
||||
},
|
||||
min = 1,
|
||||
max = 10,
|
||||
stepIncrement = 1,
|
||||
enabledIf = { prefs.emoji.suggestionEnabled.isTrue() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package dev.patrickgold.florisboard.app.settings.smartbar
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.enumDisplayEntriesOf
|
||||
import dev.patrickgold.florisboard.ime.smartbar.CandidatesDisplayMode
|
||||
@@ -64,11 +65,16 @@ fun SmartbarScreen() = FlorisScreen {
|
||||
prefs.smartbar.layout isEqualTo SmartbarLayout.SUGGESTIONS_ACTIONS_EXTENDED
|
||||
},
|
||||
)
|
||||
// TODO: schedule to remove this preference in the future, but keep it for now so users
|
||||
// know why the setting is not available anymore. Also force enable it for UI display.
|
||||
SideEffect {
|
||||
prefs.smartbar.sharedActionsAutoExpandCollapse.set(true)
|
||||
}
|
||||
SwitchPreference(
|
||||
prefs.smartbar.sharedActionsAutoExpandCollapse,
|
||||
title = stringRes(R.string.pref__smartbar__shared_actions_auto_expand_collapse__label),
|
||||
summary = stringRes(R.string.pref__smartbar__shared_actions_auto_expand_collapse__summary),
|
||||
enabledIf = { prefs.smartbar.enabled isEqualTo true },
|
||||
summary = "[Since v0.4.1] Always enabled due to UX issues",
|
||||
enabledIf = { false },
|
||||
visibleIf = { prefs.smartbar.layout isEqualTo SmartbarLayout.SUGGESTIONS_ACTIONS_SHARED },
|
||||
)
|
||||
ListPreference(
|
||||
|
||||
@@ -31,7 +31,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.HelpOutline
|
||||
import androidx.compose.material.icons.automirrored.filled.HelpOutline
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
@@ -455,7 +455,7 @@ private fun PropertyValueEditor(
|
||||
FlorisIconButton(
|
||||
onClick = { showSyntaxHelp = !showSyntaxHelp },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = Icons.Default.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Filled.HelpOutline,
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
||||
@@ -40,8 +40,8 @@ import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
|
||||
import androidx.compose.foundation.text.selection.TextSelectionColors
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.HelpOutline
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.HelpOutline
|
||||
import androidx.compose.material.icons.filled.Pageview
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@@ -225,7 +225,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.snygg__rule_selector__pressed)
|
||||
},
|
||||
selected = pressedSelector,
|
||||
color = if (pressedSelector) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { focusSelector = !focusSelector },
|
||||
@@ -235,7 +234,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.snygg__rule_selector__focus)
|
||||
},
|
||||
selected = focusSelector,
|
||||
color = if (focusSelector) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { disabledSelector = !disabledSelector },
|
||||
@@ -244,7 +242,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.snygg__rule_selector__disabled)
|
||||
},
|
||||
selected = disabledSelector,
|
||||
color = if (disabledSelector) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -291,7 +288,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.enum__input_shift_state__unshifted)
|
||||
},
|
||||
selected = shiftStateUnshifted,
|
||||
color = if (shiftStateUnshifted) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { shiftStateShiftedManual = !shiftStateShiftedManual },
|
||||
@@ -302,7 +298,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.enum__input_shift_state__shifted_manual)
|
||||
},
|
||||
selected = shiftStateShiftedManual,
|
||||
color = if (shiftStateShiftedManual) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { shiftStateShiftedAutomatic = !shiftStateShiftedAutomatic },
|
||||
@@ -313,7 +308,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.enum__input_shift_state__shifted_automatic)
|
||||
},
|
||||
selected = shiftStateShiftedAutomatic,
|
||||
color = if (shiftStateShiftedAutomatic) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
FlorisChip(
|
||||
onClick = { shiftStateCapsLock = !shiftStateCapsLock },
|
||||
@@ -324,7 +318,6 @@ internal fun EditRuleDialog(
|
||||
else -> stringRes(R.string.enum__input_shift_state__caps_lock)
|
||||
},
|
||||
selected = shiftStateCapsLock,
|
||||
color = if (shiftStateCapsLock) MaterialTheme.colorScheme.secondary else Color.Unspecified,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -479,7 +472,7 @@ private fun EditCodeValueDialog(
|
||||
FlorisIconButton(
|
||||
onClick = { showKeyCodesHelp = !showKeyCodesHelp },
|
||||
modifier = Modifier.offset(x = 12.dp),
|
||||
icon = Icons.Default.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Filled.HelpOutline,
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
||||
@@ -48,15 +48,16 @@ import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.outlined.Backspace
|
||||
import androidx.compose.material.icons.filled.ClearAll
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.ToggleOff
|
||||
import androidx.compose.material.icons.filled.ToggleOn
|
||||
import androidx.compose.material.icons.filled.Videocam
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -87,6 +88,8 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardFileStorage
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.media.KeyboardLikeButton
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
@@ -193,6 +196,13 @@ fun ClipboardInputLayout(
|
||||
iconColor = headerStyle.foreground.solidColor(context),
|
||||
enabled = !deviceLocked && historyEnabled && !isPopupSurfaceActive(),
|
||||
)
|
||||
KeyboardLikeButton(
|
||||
inputEventDispatcher = keyboardManager.inputEventDispatcher,
|
||||
keyData = TextKeyData.DELETE,
|
||||
element = FlorisImeUi.ClipboardHeader,
|
||||
) {
|
||||
Icon(Icons.AutoMirrored.Outlined.Backspace, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +222,7 @@ fun ClipboardInputLayout(
|
||||
clip = true,
|
||||
clickAndSemanticsModifier = Modifier.combinedClickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(),
|
||||
indication = ripple(),
|
||||
enabled = popupItem == null,
|
||||
onLongClick = {
|
||||
popupItem = item
|
||||
@@ -307,7 +317,7 @@ fun ClipboardInputLayout(
|
||||
.fillMaxWidth()
|
||||
.run { if (contentScrollInsteadOfClip) this.florisVerticalScroll() else this }
|
||||
.padding(ItemPadding),
|
||||
text = text,
|
||||
text = item.displayText(),
|
||||
style = TextStyle(textDirection = TextDirection.ContentOrLtr),
|
||||
color = style.foreground.solidColor(context),
|
||||
fontSize = style.fontSize.spSize(),
|
||||
@@ -577,7 +587,7 @@ fun ClipboardInputLayout(
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
.height(FlorisImeSizing.imeUiHeight()),
|
||||
) {
|
||||
HeaderRow()
|
||||
if (deviceLocked) {
|
||||
|
||||
@@ -28,11 +28,6 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardHistoryDao
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardHistoryDatabase
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
import org.florisboard.lib.android.AndroidClipboardManager
|
||||
import org.florisboard.lib.android.AndroidClipboardManager_OnPrimaryClipChangedListener
|
||||
import org.florisboard.lib.android.setOrClearPrimaryClip
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.systemService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -45,6 +40,11 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.florisboard.lib.android.AndroidClipboardManager
|
||||
import org.florisboard.lib.android.AndroidClipboardManager_OnPrimaryClipChangedListener
|
||||
import org.florisboard.lib.android.setOrClearPrimaryClip
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.systemService
|
||||
import org.florisboard.lib.kotlin.tryOrNull
|
||||
import java.io.Closeable
|
||||
|
||||
@@ -110,7 +110,9 @@ class ClipboardManager(
|
||||
val primaryClipFlow = _primaryClipFlow.asStateFlow()
|
||||
inline var primaryClip
|
||||
get() = primaryClipFlow.value
|
||||
private set(v) { _primaryClipFlow.value = v }
|
||||
private set(v) {
|
||||
_primaryClipFlow.value = v
|
||||
}
|
||||
|
||||
init {
|
||||
systemClipboardManager.addPrimaryClipChangedListener(this)
|
||||
@@ -278,6 +280,9 @@ class ClipboardManager(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all unpinned items from the clipboard history
|
||||
*/
|
||||
fun clearHistory() {
|
||||
ioScope.launch {
|
||||
for (item in history().all) {
|
||||
@@ -287,6 +292,9 @@ class ClipboardManager(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the full clipboard history
|
||||
*/
|
||||
fun clearFullHistory() {
|
||||
ioScope.launch {
|
||||
for (item in history().all) {
|
||||
@@ -300,26 +308,15 @@ class ClipboardManager(
|
||||
/**
|
||||
* Restore the clipboard history from a [List]
|
||||
*
|
||||
* @param shouldReset if the history should be reset
|
||||
* @param items the [ClipboardItem] list with the new items
|
||||
*/
|
||||
fun restoreHistory(items: List<ClipboardItem>, shouldReset: Boolean, itemType: ItemType) {
|
||||
fun restoreHistory(items: List<ClipboardItem>) {
|
||||
ioScope.launch {
|
||||
if (shouldReset) {
|
||||
for (item in history().all) {
|
||||
item.close(appContext)
|
||||
}
|
||||
clipHistoryDao?.deleteAllFromType(itemType)
|
||||
for (item in items) {
|
||||
val currentHistory = this@ClipboardManager.history().all
|
||||
for (item in items) {
|
||||
if (!currentHistory.map { it.copy(id = 0) }.contains(item.copy(id = 0))) {
|
||||
this@ClipboardManager.insertClip(item.copy(id = 0))
|
||||
}
|
||||
} else {
|
||||
val currentHistory = this@ClipboardManager.history().all
|
||||
for (item in items) {
|
||||
if (!currentHistory.map { it.copy(id = 0) }.contains(item.copy(id = 0))) {
|
||||
this@ClipboardManager.insertClip(item.copy(id = 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +341,7 @@ class ClipboardManager(
|
||||
|
||||
fun unpinClip(item: ClipboardItem) {
|
||||
ioScope.launch {
|
||||
clipHistoryDao?.update(item.copy(isPinned = false))
|
||||
clipHistoryDao?.update(item.copy(isPinned = false))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ class FlorisCopyToClipboardActivity : ComponentActivity() {
|
||||
} else {
|
||||
val uri: Uri? =
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
@Suppress("DEPRECATION")
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM)
|
||||
} else {
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package dev.patrickgold.florisboard.ime.clipboard.provider
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipDescription.EXTRA_IS_REMOTE_DEVICE
|
||||
import android.content.ClipDescription.EXTRA_IS_SENSITIVE
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
@@ -24,6 +26,8 @@ import android.net.Uri
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore.Images.Media
|
||||
import android.provider.OpenableColumns
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.database.getStringOrNull
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.ColumnInfo
|
||||
@@ -39,9 +43,14 @@ import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverter
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.Update
|
||||
import dev.patrickgold.florisboard.R
|
||||
import kotlinx.serialization.EncodeDefault
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.android.UriSerializer
|
||||
import org.florisboard.lib.android.query
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.florisboard.lib.android.stringRes
|
||||
import org.florisboard.lib.kotlin.tryOrNull
|
||||
|
||||
private const val CLIPBOARD_HISTORY_TABLE = "clipboard_history"
|
||||
@@ -67,7 +76,7 @@ enum class ItemType(val value: Int) {
|
||||
*/
|
||||
@Serializable
|
||||
@Entity(tableName = CLIPBOARD_HISTORY_TABLE)
|
||||
data class ClipboardItem(
|
||||
data class ClipboardItem @OptIn(ExperimentalSerializationApi::class) constructor(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = BaseColumns._ID, index = true)
|
||||
var id: Long = 0,
|
||||
@@ -78,6 +87,10 @@ data class ClipboardItem(
|
||||
val creationTimestampMs: Long,
|
||||
val isPinned: Boolean,
|
||||
val mimeTypes: Array<String>,
|
||||
@EncodeDefault
|
||||
val isSensitive: Boolean = false,
|
||||
@EncodeDefault
|
||||
val isRemoteDevice: Boolean = false,
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
@@ -113,6 +126,18 @@ data class ClipboardItem(
|
||||
else -> ItemType.TEXT
|
||||
}
|
||||
|
||||
val isSensitive = if (AndroidVersion.ATLEAST_API33_T) {
|
||||
data.description?.extras?.getBoolean(EXTRA_IS_SENSITIVE) ?: false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
val isRemoteDevice = if (AndroidVersion.ATLEAST_API34_U) {
|
||||
data.description?.extras?.getBoolean(EXTRA_IS_REMOTE_DEVICE) ?: false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
val uri = if (type == ItemType.IMAGE || type == ItemType.VIDEO) {
|
||||
if (dataItem.uri.authority == ClipboardMediaProvider.AUTHORITY || !cloneUri) {
|
||||
dataItem.uri
|
||||
@@ -151,7 +176,21 @@ data class ClipboardItem(
|
||||
}
|
||||
}
|
||||
|
||||
return ClipboardItem(0, type, text, uri, System.currentTimeMillis(), false, mimeTypes)
|
||||
return ClipboardItem(0, type, text, uri, System.currentTimeMillis(), false, mimeTypes, isSensitive, isRemoteDevice)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
inline fun displayText(): String {
|
||||
val context = LocalContext.current
|
||||
return displayText(context)
|
||||
}
|
||||
|
||||
fun displayText(context: Context): String {
|
||||
return if (isSensitive) {
|
||||
context.stringRes(R.string.clipboard__sensitive_clip_content)
|
||||
} else {
|
||||
stringRepresentation()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +332,7 @@ interface ClipboardHistoryDao {
|
||||
fun deleteAllUnpinned()
|
||||
}
|
||||
|
||||
@Database(entities = [ClipboardItem::class], version = 2)
|
||||
@Database(entities = [ClipboardItem::class], version = 3)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class ClipboardHistoryDatabase : RoomDatabase() {
|
||||
abstract fun clipboardItemDao(): ClipboardHistoryDao
|
||||
|
||||
@@ -61,7 +61,28 @@ object ClipboardFileStorage {
|
||||
return context.clipboardFilesDir.subFile(id.toString())
|
||||
}
|
||||
|
||||
fun instertFileFromBackup(context: Context, file: FsFile) {
|
||||
file.copyTo(context.clipboardFilesDir.subFile(file.name), overwrite = false)
|
||||
|
||||
/**
|
||||
* Insert file from backup if not existing
|
||||
*
|
||||
* @param context the application context
|
||||
* @param file the file to be inserted
|
||||
*/
|
||||
fun insertFileFromBackupIfNotExisting(context: Context, file: FsFile) {
|
||||
if (!context.clipboardFilesDir.subFile(file.name).isFile) {
|
||||
file.copyTo(context.clipboardFilesDir.subFile(file.name), overwrite = false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all files from the clipboard subdirectory
|
||||
*
|
||||
* @param context the application context
|
||||
*/
|
||||
fun resetClipboardFileStorage(context: Context) {
|
||||
context.clipboardFilesDir.listFiles()?.forEach {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,15 @@ package dev.patrickgold.florisboard.ime.keyboard
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowRightAlt
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowRightAlt
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardReturn
|
||||
import androidx.compose.material.icons.automirrored.filled.Redo
|
||||
import androidx.compose.material.icons.automirrored.filled.Send
|
||||
import androidx.compose.material.icons.automirrored.filled.Undo
|
||||
import androidx.compose.material.icons.automirrored.outlined.Assignment
|
||||
import androidx.compose.material.icons.automirrored.outlined.Backspace
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.ContentCopy
|
||||
import androidx.compose.material.icons.filled.ContentCut
|
||||
@@ -27,24 +35,16 @@ import androidx.compose.material.icons.filled.DeleteSweep
|
||||
import androidx.compose.material.icons.filled.Done
|
||||
import androidx.compose.material.icons.filled.FontDownload
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material.icons.filled.KeyboardCapslock
|
||||
import androidx.compose.material.icons.filled.KeyboardReturn
|
||||
import androidx.compose.material.icons.filled.KeyboardVoice
|
||||
import androidx.compose.material.icons.filled.Language
|
||||
import androidx.compose.material.icons.filled.MoreHoriz
|
||||
import androidx.compose.material.icons.filled.Redo
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.SelectAll
|
||||
import androidx.compose.material.icons.filled.Send
|
||||
import androidx.compose.material.icons.filled.SentimentSatisfiedAlt
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.SpaceBar
|
||||
import androidx.compose.material.icons.filled.Undo
|
||||
import androidx.compose.material.icons.outlined.Assignment
|
||||
import androidx.compose.material.icons.outlined.Backspace
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.DisplayLanguageNamesIn
|
||||
@@ -179,10 +179,10 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
|
||||
val evaluator = this
|
||||
return when (data.code) {
|
||||
KeyCode.ARROW_LEFT -> {
|
||||
Icons.Default.KeyboardArrowLeft
|
||||
Icons.AutoMirrored.Filled.KeyboardArrowLeft
|
||||
}
|
||||
KeyCode.ARROW_RIGHT -> {
|
||||
Icons.Default.KeyboardArrowRight
|
||||
Icons.AutoMirrored.Filled.KeyboardArrowRight
|
||||
}
|
||||
KeyCode.ARROW_UP -> {
|
||||
Icons.Default.KeyboardArrowUp
|
||||
@@ -213,23 +213,23 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
|
||||
Icons.Default.KeyboardVoice
|
||||
}
|
||||
KeyCode.DELETE -> {
|
||||
Icons.Outlined.Backspace
|
||||
Icons.AutoMirrored.Outlined.Backspace
|
||||
}
|
||||
KeyCode.ENTER -> {
|
||||
val imeOptions = evaluator.editorInfo.imeOptions
|
||||
val inputAttributes = evaluator.editorInfo.inputAttributes
|
||||
if (imeOptions.flagNoEnterAction || inputAttributes.flagTextMultiLine) {
|
||||
Icons.Default.KeyboardReturn
|
||||
Icons.AutoMirrored.Filled.KeyboardReturn
|
||||
} else {
|
||||
when (imeOptions.action) {
|
||||
ImeOptions.Action.DONE -> Icons.Default.Done
|
||||
ImeOptions.Action.GO -> Icons.Default.ArrowRightAlt
|
||||
ImeOptions.Action.NEXT -> Icons.Default.ArrowRightAlt
|
||||
ImeOptions.Action.NONE -> Icons.Default.KeyboardReturn
|
||||
ImeOptions.Action.PREVIOUS -> Icons.Default.ArrowRightAlt
|
||||
ImeOptions.Action.GO -> Icons.AutoMirrored.Filled.ArrowRightAlt
|
||||
ImeOptions.Action.NEXT -> Icons.AutoMirrored.Filled.ArrowRightAlt
|
||||
ImeOptions.Action.NONE -> Icons.AutoMirrored.Filled.KeyboardReturn
|
||||
ImeOptions.Action.PREVIOUS -> Icons.AutoMirrored.Filled.ArrowRightAlt
|
||||
ImeOptions.Action.SEARCH -> Icons.Default.Search
|
||||
ImeOptions.Action.SEND -> Icons.Default.Send
|
||||
ImeOptions.Action.UNSPECIFIED -> Icons.Default.KeyboardReturn
|
||||
ImeOptions.Action.SEND -> Icons.AutoMirrored.Filled.Send
|
||||
ImeOptions.Action.UNSPECIFIED -> Icons.AutoMirrored.Filled.KeyboardReturn
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,7 +237,7 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
|
||||
Icons.Default.SentimentSatisfiedAlt
|
||||
}
|
||||
KeyCode.IME_UI_MODE_CLIPBOARD -> {
|
||||
Icons.Outlined.Assignment
|
||||
Icons.AutoMirrored.Outlined.Assignment
|
||||
}
|
||||
KeyCode.LANGUAGE_SWITCH -> {
|
||||
Icons.Default.Language
|
||||
@@ -263,10 +263,10 @@ fun ComputingEvaluator.computeImageVector(data: KeyData): ImageVector? {
|
||||
}
|
||||
}
|
||||
KeyCode.UNDO -> {
|
||||
Icons.Default.Undo
|
||||
Icons.AutoMirrored.Filled.Undo
|
||||
}
|
||||
KeyCode.REDO -> {
|
||||
Icons.Default.Redo
|
||||
Icons.AutoMirrored.Filled.Redo
|
||||
}
|
||||
KeyCode.TOGGLE_ACTIONS_OVERFLOW -> {
|
||||
Icons.Default.MoreHoriz
|
||||
|
||||
@@ -142,9 +142,15 @@ class KeyboardManager(context: Context) : InputKeyEventReceiver {
|
||||
prefs.keyboard.utilityKeyEnabled.observeForever {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
prefs.keyboard.utilityKeyAction.observeForever {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
activeState.collectLatestIn(scope) {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
subtypeManager.subtypesFlow.collectLatestIn(scope) {
|
||||
updateActiveEvaluators()
|
||||
}
|
||||
subtypeManager.activeSubtypeFlow.collectLatestIn(scope) {
|
||||
reevaluateInputShiftState()
|
||||
updateActiveEvaluators()
|
||||
|
||||
@@ -29,7 +29,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Backspace
|
||||
import androidx.compose.material.icons.automirrored.outlined.Backspace
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -101,7 +101,7 @@ fun MediaInputLayout(
|
||||
inputEventDispatcher = keyboardManager.inputEventDispatcher,
|
||||
keyData = TextKeyData.DELETE,
|
||||
) {
|
||||
Icon(imageVector = Icons.Outlined.Backspace, contentDescription = null)
|
||||
Icon(imageVector = Icons.AutoMirrored.Outlined.Backspace, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,12 +113,13 @@ internal fun KeyboardLikeButton(
|
||||
modifier: Modifier = Modifier,
|
||||
inputEventDispatcher: InputEventDispatcher,
|
||||
keyData: KeyData,
|
||||
element: String = FlorisImeUi.EmojiKey,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
var isPressed by remember { mutableStateOf(false) }
|
||||
val keyStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.EmojiKey,
|
||||
element = element,
|
||||
code = keyData.code,
|
||||
isPressed = isPressed,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,11 @@ import dev.patrickgold.florisboard.ime.keyboard.KeyData
|
||||
import dev.patrickgold.florisboard.ime.popup.PopupSet
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyType
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import java.util.stream.IntStream
|
||||
import kotlin.streams.toList
|
||||
|
||||
@@ -42,7 +47,7 @@ enum class EmojiHairStyle(val id: Int) {
|
||||
BALD(0x1F9B3);
|
||||
}
|
||||
|
||||
data class Emoji(val value: String, val name: String, val keywords: List<String>) : KeyData {
|
||||
class Emoji(val value: String, val name: String, val keywords: List<String>) : KeyData {
|
||||
override val type = KeyType.CHARACTER
|
||||
override val code = KeyCode.UNSPECIFIED
|
||||
override val label = value
|
||||
@@ -73,4 +78,24 @@ data class Emoji(val value: String, val name: String, val keywords: List<String>
|
||||
override fun toString(): String {
|
||||
return "Emoji { value=$value, name=$name, keywords=$keywords }"
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is Emoji && value == other.value
|
||||
}
|
||||
|
||||
object ValueOnlySerializer : KSerializer<Emoji> {
|
||||
override val descriptor = PrimitiveSerialDescriptor("EmojiValueOnly", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Emoji) {
|
||||
encoder.encodeString(value.value)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Emoji {
|
||||
return Emoji(decoder.decodeString(), "", emptyList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,10 +95,11 @@ data class EmojiData(
|
||||
// Assume it is a data line
|
||||
val data = line.split(";")
|
||||
if (data.size == 3) {
|
||||
val base = emojiEditorList?.first()
|
||||
val emoji = Emoji(
|
||||
value = data[0].trim(),
|
||||
name = data[1].trim(),
|
||||
keywords = data[2].split("|").map { it.trim() }
|
||||
name = base?.name ?: data[1].trim(),
|
||||
keywords = data[2].split("|").map { it.trim() },
|
||||
)
|
||||
if (emojiEditorList != null) {
|
||||
emojiEditorList!!.add(emoji)
|
||||
@@ -113,6 +114,14 @@ data class EmojiData(
|
||||
|
||||
for (category in byCategory.keys) {
|
||||
for (emojiSet in byCategory[category]!!) {
|
||||
if (emojiSet.emojis.size == 1) {
|
||||
// No variations provided, we fallback to using the base for all skin tones
|
||||
val base = emojiSet.emojis.first()
|
||||
for (skinTone in EmojiSkinTone.entries) {
|
||||
bySkinTone[skinTone]!!.add(base)
|
||||
}
|
||||
continue
|
||||
}
|
||||
for (emoji in emojiSet.emojis) {
|
||||
bySkinTone[emoji.skinTone]!!.add(emoji)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.media.emoji
|
||||
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceSerializer
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
data class EmojiHistory(
|
||||
val pinned: List<@Serializable(with = Emoji.ValueOnlySerializer::class) Emoji>,
|
||||
val recent: List<@Serializable(with = Emoji.ValueOnlySerializer::class) Emoji>,
|
||||
) {
|
||||
fun edit(): Editor {
|
||||
return Editor(pinned.toMutableList(), recent.toMutableList())
|
||||
}
|
||||
|
||||
data class Editor(
|
||||
val pinned: MutableList<Emoji>,
|
||||
val recent: MutableList<Emoji>,
|
||||
) {
|
||||
fun build(): EmojiHistory {
|
||||
return EmojiHistory(pinned.toList(), recent.toList())
|
||||
}
|
||||
}
|
||||
|
||||
enum class UpdateStrategy(val isAutomatic: Boolean, val isPrepend: Boolean) {
|
||||
AUTO_SORT_PREPEND(isAutomatic = true, isPrepend = true),
|
||||
AUTO_SORT_APPEND(isAutomatic = true, isPrepend = false),
|
||||
MANUAL_SORT_PREPEND(isAutomatic = false, isPrepend = true),
|
||||
MANUAL_SORT_APPEND(isAutomatic = false, isPrepend = false);
|
||||
}
|
||||
|
||||
object Serializer : PreferenceSerializer<EmojiHistory> {
|
||||
override fun serialize(value: EmojiHistory): String {
|
||||
return Json.encodeToString(value)
|
||||
}
|
||||
|
||||
override fun deserialize(value: String): EmojiHistory {
|
||||
try {
|
||||
return Json.decodeFromString(value)
|
||||
} catch (e: Exception) {
|
||||
flogError { "Failed to deserialize EmojiHistory: $e" }
|
||||
return Empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Empty = EmojiHistory(emptyList(), emptyList())
|
||||
|
||||
@Suppress("ConstPropertyName")
|
||||
const val MaxSizeUnlimited: Int = 0
|
||||
}
|
||||
}
|
||||
|
||||
object EmojiHistoryHelper {
|
||||
private var emojiGuard = Mutex(locked = false)
|
||||
|
||||
suspend fun markEmojiUsed(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
|
||||
val dataMut = prefs.emoji.historyData.get().edit()
|
||||
val pinnedUS = prefs.emoji.historyPinnedUpdateStrategy.get()
|
||||
val recentUS = prefs.emoji.historyRecentUpdateStrategy.get()
|
||||
val pinnedMaxSize = prefs.emoji.historyPinnedMaxSize.get().let { maxSize ->
|
||||
if (maxSize == EmojiHistory.MaxSizeUnlimited) Int.MAX_VALUE else maxSize
|
||||
}
|
||||
val recentMaxSize = prefs.emoji.historyRecentMaxSize.get().let { maxSize ->
|
||||
if (maxSize == EmojiHistory.MaxSizeUnlimited) Int.MAX_VALUE else maxSize
|
||||
}
|
||||
|
||||
val pinnedIndex = dataMut.pinned.indexOf(emoji)
|
||||
if (pinnedIndex != -1) {
|
||||
if (pinnedUS.isAutomatic) {
|
||||
dataMut.pinned.removeAt(pinnedIndex)
|
||||
dataMut.pinned.addWithStrategy(pinnedUS, emoji)
|
||||
} else {
|
||||
// manual sort, keep item in place
|
||||
}
|
||||
} else {
|
||||
val recentIndex = dataMut.recent.indexOf(emoji)
|
||||
if (recentIndex != -1) {
|
||||
if (recentUS.isAutomatic) {
|
||||
dataMut.recent.removeAt(recentIndex)
|
||||
dataMut.recent.addWithStrategy(recentUS, emoji)
|
||||
} else {
|
||||
// manual sort, keep item in place
|
||||
}
|
||||
} else {
|
||||
dataMut.recent.addWithStrategy(recentUS, emoji)
|
||||
}
|
||||
}
|
||||
|
||||
prefs.emoji.historyData.set(
|
||||
EmojiHistory(
|
||||
pinned = dataMut.pinned.takeWithStrategy(pinnedUS, pinnedMaxSize),
|
||||
recent = dataMut.recent.takeWithStrategy(recentUS, recentMaxSize),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun pinEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
|
||||
val dataMut = prefs.emoji.historyData.get().edit()
|
||||
val pinnedUS = prefs.emoji.historyPinnedUpdateStrategy.get()
|
||||
|
||||
val recentIndex = dataMut.recent.indexOf(emoji)
|
||||
if (recentIndex != -1) {
|
||||
dataMut.recent.removeAt(recentIndex)
|
||||
dataMut.pinned.addWithStrategy(pinnedUS, emoji)
|
||||
}
|
||||
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun unpinEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
|
||||
val dataMut = prefs.emoji.historyData.get().edit()
|
||||
val recentUS = prefs.emoji.historyRecentUpdateStrategy.get()
|
||||
|
||||
val pinnedIndex = dataMut.pinned.indexOf(emoji)
|
||||
if (pinnedIndex != -1) {
|
||||
dataMut.pinned.removeAt(pinnedIndex)
|
||||
dataMut.recent.addWithStrategy(recentUS, emoji)
|
||||
}
|
||||
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun moveEmoji(prefs: AppPrefs, emoji: Emoji, offset: Int) = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get() || offset == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val dataMut = prefs.emoji.historyData.get().edit()
|
||||
|
||||
val pinnedIndex = dataMut.pinned.indexOf(emoji)
|
||||
if (pinnedIndex != -1) {
|
||||
dataMut.pinned.move(pinnedIndex, offset)
|
||||
} else {
|
||||
val recentIndex = dataMut.recent.indexOf(emoji)
|
||||
if (recentIndex != -1) {
|
||||
dataMut.recent.move(recentIndex, offset)
|
||||
}
|
||||
}
|
||||
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
suspend fun removeEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
if (!prefs.emoji.historyEnabled.get()) {
|
||||
return
|
||||
}
|
||||
|
||||
val dataMut = prefs.emoji.historyData.get().edit()
|
||||
|
||||
val pinnedIndex = dataMut.pinned.indexOf(emoji)
|
||||
if (pinnedIndex != -1) {
|
||||
dataMut.pinned.removeAt(pinnedIndex)
|
||||
} else {
|
||||
val recentIndex = dataMut.recent.indexOf(emoji)
|
||||
if (recentIndex != -1) {
|
||||
dataMut.recent.removeAt(recentIndex)
|
||||
}
|
||||
}
|
||||
|
||||
prefs.emoji.historyData.set(dataMut.build())
|
||||
}
|
||||
|
||||
private fun MutableList<Emoji>.addWithStrategy(strategy: EmojiHistory.UpdateStrategy, emoji: Emoji) {
|
||||
if (strategy.isPrepend) {
|
||||
add(0, emoji)
|
||||
} else {
|
||||
add(emoji)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<Emoji>.takeWithStrategy(
|
||||
strategy: EmojiHistory.UpdateStrategy,
|
||||
n: Int,
|
||||
): List<Emoji> {
|
||||
return if (strategy.isPrepend) {
|
||||
take(n)
|
||||
} else {
|
||||
takeLast(n)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<Emoji>.move(itemIndex: Int, offset: Int) {
|
||||
val newIndex = (itemIndex + offset).coerceIn(0..<size)
|
||||
val item = removeAt(itemIndex)
|
||||
if (newIndex == size) {
|
||||
add(item)
|
||||
} else {
|
||||
add(newIndex, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,14 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.shape.GenericShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
import androidx.compose.material.icons.outlined.PushPin
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.TabRowDefaults
|
||||
@@ -61,6 +67,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
@@ -85,12 +92,11 @@ import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.florisScrollbar
|
||||
import dev.patrickgold.florisboard.lib.compose.header
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.florisboard.lib.android.AndroidKeyguardManager
|
||||
import org.florisboard.lib.android.showShortToast
|
||||
import org.florisboard.lib.android.systemService
|
||||
@@ -117,6 +123,12 @@ private val VariantsTriangleShapeRtl = GenericShape { size, _ ->
|
||||
lineTo(x = 0f, y = size.height)
|
||||
}
|
||||
|
||||
data class EmojiMappingForView(
|
||||
val pinned: List<EmojiSet>,
|
||||
val recent: List<EmojiSet>,
|
||||
val simple: List<EmojiSet>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun EmojiPaletteView(
|
||||
fullEmojiMappings: EmojiData,
|
||||
@@ -150,16 +162,61 @@ fun EmojiPaletteView(
|
||||
|
||||
val deviceLocked = androidKeyguardManager.let { it.isDeviceLocked || it.isKeyguardLocked }
|
||||
|
||||
var activeCategory by remember { mutableStateOf(EmojiCategory.RECENTLY_USED) }
|
||||
val lazyListState = rememberLazyGridState()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val preferredSkinTone by prefs.media.emojiPreferredSkinTone.observeAsState()
|
||||
val preferredSkinTone by prefs.emoji.preferredSkinTone.observeAsState()
|
||||
val emojiHistoryEnabled by prefs.emoji.historyEnabled.observeAsState()
|
||||
val fontSizeMultiplier = prefs.keyboard.fontSizeMultiplier()
|
||||
val emojiKeyStyle = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiKey)
|
||||
val emojiKeyFontSize = emojiKeyStyle.fontSize.spSize(default = EmojiDefaultFontSize) safeTimes fontSizeMultiplier
|
||||
val contentColor = emojiKeyStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
|
||||
var activeCategory by remember(emojiHistoryEnabled) {
|
||||
if (emojiHistoryEnabled) {
|
||||
mutableStateOf(EmojiCategory.RECENTLY_USED)
|
||||
} else {
|
||||
mutableStateOf(EmojiCategory.SMILEYS_EMOTION)
|
||||
}
|
||||
}
|
||||
var recentlyUsedVersion by remember { mutableIntStateOf(0) }
|
||||
val lazyListState = rememberLazyGridState()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
@Composable
|
||||
fun GridHeader(text: String) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
text = text,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = contentColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmojiKeyWrapper(
|
||||
emojiSet: EmojiSet,
|
||||
isPinned: Boolean = false,
|
||||
isRecent: Boolean = false,
|
||||
) {
|
||||
EmojiKey(
|
||||
emojiSet = emojiSet,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
preferredSkinTone = preferredSkinTone,
|
||||
isPinned = isPinned,
|
||||
isRecent = isRecent,
|
||||
contentColor = contentColor,
|
||||
fontSize = emojiKeyFontSize,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
onEmojiInput = { emoji ->
|
||||
keyboardManager.inputEventDispatcher.sendDownUp(emoji)
|
||||
scope.launch {
|
||||
EmojiHistoryHelper.markEmojiUsed(prefs, emoji)
|
||||
}
|
||||
},
|
||||
onHistoryAction = {
|
||||
recentlyUsedVersion++
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Column(modifier = modifier) {
|
||||
EmojiCategoriesTabRow(
|
||||
activeCategory = activeCategory,
|
||||
@@ -167,6 +224,7 @@ fun EmojiPaletteView(
|
||||
scope.launch { lazyListState.scrollToItem(0) }
|
||||
activeCategory = category
|
||||
},
|
||||
emojiHistoryEnabled = emojiHistoryEnabled,
|
||||
)
|
||||
|
||||
Box(
|
||||
@@ -174,16 +232,25 @@ fun EmojiPaletteView(
|
||||
.fillMaxWidth()
|
||||
.weight(1f),
|
||||
) {
|
||||
var recentlyUsedVersion by remember { mutableIntStateOf(0) }
|
||||
val emojiMapping = if (activeCategory == EmojiCategory.RECENTLY_USED) {
|
||||
// Purposely using remember here to prevent recomposition, as this would cause rapid
|
||||
// emoji changes for the user when in recently used category.
|
||||
remember(recentlyUsedVersion) {
|
||||
prefs.media.emojiRecentlyUsed.get().map { EmojiSet(listOf(it)) }
|
||||
val data = prefs.emoji.historyData.get()
|
||||
EmojiMappingForView(
|
||||
pinned = data.pinned.map { EmojiSet(listOf(it)) },
|
||||
recent = data.recent.map { EmojiSet(listOf(it)) },
|
||||
simple = emptyList(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
emojiMappings[activeCategory]!!
|
||||
EmojiMappingForView(
|
||||
pinned = emptyList(),
|
||||
recent = emptyList(),
|
||||
simple = emojiMappings[activeCategory]!!,
|
||||
)
|
||||
}
|
||||
val isEmojiHistoryEmpty = emojiMapping.pinned.isEmpty() && emojiMapping.recent.isEmpty()
|
||||
if (activeCategory == EmojiCategory.RECENTLY_USED && deviceLocked) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -191,29 +258,28 @@ fun EmojiPaletteView(
|
||||
.padding(all = 8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringRes(R.string.emoji__recently_used__phone_locked_message),
|
||||
text = stringRes(R.string.emoji__history__phone_locked_message),
|
||||
color = contentColor,
|
||||
)
|
||||
}
|
||||
} else if (activeCategory == EmojiCategory.RECENTLY_USED && emojiMapping.isEmpty()) {
|
||||
} else if (activeCategory == EmojiCategory.RECENTLY_USED && isEmojiHistoryEmpty) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(all = 8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringRes(R.string.emoji__recently_used__empty_message),
|
||||
text = stringRes(R.string.emoji__history__empty_message),
|
||||
color = contentColor,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
text = stringRes(R.string.emoji__recently_used__removal_tip),
|
||||
text = stringRes(R.string.emoji__history__usage_tip),
|
||||
color = contentColor,
|
||||
fontStyle = FontStyle.Italic,
|
||||
)
|
||||
}
|
||||
}
|
||||
else key(emojiMapping) {
|
||||
} else key(emojiMapping) {
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
LazyVerticalGrid(
|
||||
modifier = Modifier
|
||||
@@ -222,35 +288,26 @@ fun EmojiPaletteView(
|
||||
columns = GridCells.Adaptive(minSize = EmojiBaseWidth),
|
||||
state = lazyListState,
|
||||
) {
|
||||
items(emojiMapping) { emojiSet ->
|
||||
EmojiKey(
|
||||
emojiSet = emojiSet,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
preferredSkinTone = preferredSkinTone,
|
||||
contentColor = contentColor,
|
||||
fontSize = emojiKeyFontSize,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
onEmojiInput = { emoji ->
|
||||
keyboardManager.inputEventDispatcher.sendDownUp(emoji)
|
||||
scope.launch {
|
||||
EmojiRecentlyUsedHelper.addEmoji(prefs, emoji)
|
||||
}
|
||||
},
|
||||
onLongPress = { emoji ->
|
||||
if (activeCategory == EmojiCategory.RECENTLY_USED) {
|
||||
scope.launch {
|
||||
EmojiRecentlyUsedHelper.removeEmoji(prefs, emoji)
|
||||
recentlyUsedVersion++
|
||||
withContext(Dispatchers.Main) {
|
||||
context.showShortToast(
|
||||
R.string.emoji__recently_used__removal_success_message,
|
||||
"emoji" to emoji.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
if (emojiMapping.pinned.isNotEmpty()) {
|
||||
header("header_pinned") {
|
||||
GridHeader(text = stringRes(R.string.emoji__history__pinned))
|
||||
}
|
||||
items(emojiMapping.pinned) { emojiSet ->
|
||||
EmojiKeyWrapper(emojiSet, isPinned = true)
|
||||
}
|
||||
}
|
||||
if (emojiMapping.recent.isNotEmpty()) {
|
||||
header("header_recent") {
|
||||
GridHeader(text = stringRes(R.string.emoji__history__recent))
|
||||
}
|
||||
items(emojiMapping.recent) { emojiSet ->
|
||||
EmojiKeyWrapper(emojiSet, isRecent = true)
|
||||
}
|
||||
}
|
||||
if (emojiMapping.simple.isNotEmpty()) {
|
||||
items(emojiMapping.simple) { emojiSet ->
|
||||
EmojiKeyWrapper(emojiSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,6 +320,7 @@ fun EmojiPaletteView(
|
||||
private fun EmojiCategoriesTabRow(
|
||||
activeCategory: EmojiCategory,
|
||||
onCategoryChange: (EmojiCategory) -> Unit,
|
||||
emojiHistoryEnabled: Boolean,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
@@ -271,7 +329,11 @@ private fun EmojiCategoriesTabRow(
|
||||
val unselectedContentColor = tabStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
val selectedContentColor = tabStyleFocused.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor())
|
||||
|
||||
val selectedTabIndex = EmojiCategoryValues.indexOf(activeCategory)
|
||||
val selectedTabIndex = if (emojiHistoryEnabled) {
|
||||
EmojiCategoryValues.indexOf(activeCategory)
|
||||
} else {
|
||||
EmojiCategoryValues.indexOf(activeCategory) - 1
|
||||
}
|
||||
TabRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -288,6 +350,9 @@ private fun EmojiCategoriesTabRow(
|
||||
},
|
||||
) {
|
||||
for (category in EmojiCategoryValues) {
|
||||
if (category == EmojiCategory.RECENTLY_USED && !emojiHistoryEnabled) {
|
||||
continue
|
||||
}
|
||||
Tab(
|
||||
onClick = {
|
||||
inputFeedbackController.keyPress(TextKeyData.UNSPECIFIED)
|
||||
@@ -311,11 +376,13 @@ private fun EmojiKey(
|
||||
emojiSet: EmojiSet,
|
||||
emojiCompatInstance: EmojiCompat?,
|
||||
preferredSkinTone: EmojiSkinTone,
|
||||
isPinned: Boolean,
|
||||
isRecent: Boolean,
|
||||
contentColor: Color,
|
||||
fontSize: TextUnit,
|
||||
fontSizeMultiplier: Float,
|
||||
onEmojiInput: (Emoji) -> Unit,
|
||||
onLongPress: (Emoji) -> Unit,
|
||||
onHistoryAction: () -> Unit,
|
||||
) {
|
||||
val inputFeedbackController = LocalInputFeedbackController.current
|
||||
val base = emojiSet.base(withSkinTone = preferredSkinTone)
|
||||
@@ -335,8 +402,7 @@ private fun EmojiKey(
|
||||
},
|
||||
onLongPress = {
|
||||
inputFeedbackController.keyLongPress(TextKeyData.UNSPECIFIED)
|
||||
onLongPress(base)
|
||||
if (variations.isNotEmpty()) {
|
||||
if (variations.isNotEmpty() || isPinned || isRecent) {
|
||||
showVariantsBox = true
|
||||
}
|
||||
},
|
||||
@@ -350,7 +416,7 @@ private fun EmojiKey(
|
||||
color = contentColor,
|
||||
fontSize = fontSize,
|
||||
)
|
||||
if (variations.isNotEmpty()) {
|
||||
if (variations.isNotEmpty() || isPinned || isRecent) {
|
||||
val shape = when (LocalLayoutDirection.current) {
|
||||
LayoutDirection.Ltr -> VariantsTriangleShapeLtr
|
||||
LayoutDirection.Rtl -> VariantsTriangleShapeRtl
|
||||
@@ -364,19 +430,34 @@ private fun EmojiKey(
|
||||
)
|
||||
}
|
||||
|
||||
EmojiVariationsPopup(
|
||||
variations = variations,
|
||||
visible = showVariantsBox,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
onEmojiTap = { emoji ->
|
||||
onEmojiInput(emoji)
|
||||
showVariantsBox = false
|
||||
},
|
||||
onDismiss = {
|
||||
showVariantsBox = false
|
||||
},
|
||||
)
|
||||
if (isPinned || isRecent) {
|
||||
EmojiHistoryPopup(
|
||||
emoji = base,
|
||||
visible = showVariantsBox,
|
||||
isCurrentlyPinned = isPinned,
|
||||
onHistoryAction = {
|
||||
onHistoryAction()
|
||||
showVariantsBox = false
|
||||
},
|
||||
onDismiss = {
|
||||
showVariantsBox = false
|
||||
},
|
||||
)
|
||||
} else {
|
||||
EmojiVariationsPopup(
|
||||
variations = variations,
|
||||
visible = showVariantsBox,
|
||||
emojiCompatInstance = emojiCompatInstance,
|
||||
fontSizeMultiplier = fontSizeMultiplier,
|
||||
onEmojiTap = { emoji ->
|
||||
onEmojiInput(emoji)
|
||||
showVariantsBox = false
|
||||
},
|
||||
onDismiss = {
|
||||
showVariantsBox = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,6 +515,113 @@ private fun EmojiVariationsPopup(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun EmojiHistoryPopup(
|
||||
emoji: Emoji,
|
||||
visible: Boolean,
|
||||
isCurrentlyPinned: Boolean,
|
||||
onHistoryAction: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val scope = rememberCoroutineScope()
|
||||
val popupStyle = FlorisImeTheme.style.get(element = FlorisImeUi.EmojiKeyPopup)
|
||||
val emojiKeyHeight = FlorisImeSizing.smartbarHeight
|
||||
val context = LocalContext.current
|
||||
val pinnedUS by prefs.emoji.historyPinnedUpdateStrategy.observeAsState()
|
||||
val recentUS by prefs.emoji.historyRecentUpdateStrategy.observeAsState()
|
||||
val showMoveLeft = isCurrentlyPinned && !pinnedUS.isAutomatic || !recentUS.isAutomatic
|
||||
val showMoveRight = isCurrentlyPinned && !pinnedUS.isAutomatic || !recentUS.isAutomatic
|
||||
|
||||
@Composable
|
||||
fun Action(icon: ImageVector, action: suspend () -> Unit) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures {
|
||||
scope.launch {
|
||||
action()
|
||||
onHistoryAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
.width(EmojiBaseWidth)
|
||||
.height(emojiKeyHeight)
|
||||
.padding(all = 4.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = popupStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val numActions = 1
|
||||
if (visible) {
|
||||
Popup(
|
||||
alignment = Alignment.TopCenter,
|
||||
offset = with(LocalDensity.current) {
|
||||
val y = -emojiKeyHeight * ceil(numActions / 6f)
|
||||
IntOffset(x = 0, y = y.toPx().toInt())
|
||||
},
|
||||
onDismissRequest = onDismiss,
|
||||
) {
|
||||
FlowRow(
|
||||
modifier = Modifier
|
||||
.widthIn(max = EmojiBaseWidth * 6)
|
||||
.snyggShadow(popupStyle)
|
||||
.snyggBorder(context, popupStyle)
|
||||
.snyggBackground(context, popupStyle, fallbackColor = FlorisImeTheme.fallbackSurfaceColor()),
|
||||
) {
|
||||
if (isCurrentlyPinned) {
|
||||
Action(
|
||||
icon = Icons.Outlined.PushPin,
|
||||
action = {
|
||||
EmojiHistoryHelper.unpinEmoji(prefs, emoji)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Action(
|
||||
icon = Icons.Outlined.PushPin,
|
||||
action = {
|
||||
EmojiHistoryHelper.pinEmoji(prefs, emoji)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (showMoveLeft) {
|
||||
Action(
|
||||
icon = Icons.AutoMirrored.Default.KeyboardArrowLeft,
|
||||
action = {
|
||||
EmojiHistoryHelper.moveEmoji(prefs, emoji, -1)
|
||||
},
|
||||
)
|
||||
}
|
||||
if (showMoveRight) {
|
||||
Action(
|
||||
icon = Icons.AutoMirrored.Default.KeyboardArrowRight,
|
||||
action = {
|
||||
EmojiHistoryHelper.moveEmoji(prefs, emoji, 1)
|
||||
},
|
||||
)
|
||||
}
|
||||
Action(
|
||||
icon = Icons.Outlined.Delete,
|
||||
action = {
|
||||
EmojiHistoryHelper.removeEmoji(prefs, emoji)
|
||||
context.showShortToast(
|
||||
R.string.emoji__history__removal_success_message,
|
||||
"emoji" to emoji.value,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmojiText(
|
||||
text: String,
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.media.emoji
|
||||
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceSerializer
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
object EmojiRecentlyUsedHelper {
|
||||
private const val DELIMITER = ";"
|
||||
|
||||
private var emojiGuard = Mutex(locked = false)
|
||||
|
||||
suspend fun addEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
val maxSize = prefs.media.emojiRecentlyUsedMaxSize.get()
|
||||
val list = prefs.media.emojiRecentlyUsed.get().toMutableList()
|
||||
list.add(0, emoji)
|
||||
if (maxSize > 0) {
|
||||
while (list.size > maxSize) {
|
||||
list.removeLast()
|
||||
}
|
||||
}
|
||||
prefs.media.emojiRecentlyUsed.set(list.distinctBy { it.value })
|
||||
}
|
||||
|
||||
suspend fun removeEmoji(prefs: AppPrefs, emoji: Emoji) = emojiGuard.withLock {
|
||||
val list = prefs.media.emojiRecentlyUsed.get().toMutableList()
|
||||
list.remove(emoji)
|
||||
prefs.media.emojiRecentlyUsed.set(list.distinctBy { it.value })
|
||||
}
|
||||
|
||||
object Serializer : PreferenceSerializer<List<Emoji>> {
|
||||
override fun serialize(value: List<Emoji>): String {
|
||||
return value.joinToString(DELIMITER) { it.value }
|
||||
}
|
||||
|
||||
override fun deserialize(value: String): List<Emoji> {
|
||||
return value.split(DELIMITER).mapNotNull { rawValue ->
|
||||
rawValue.trim().let { if (it.isBlank()) null else Emoji(it.trim(), "", emptyList()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.media.emoji
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -13,10 +29,6 @@ import dev.patrickgold.florisboard.ime.nlp.SuggestionProvider
|
||||
import dev.patrickgold.florisboard.lib.FlorisLocale
|
||||
import io.github.reactivecircus.cache4k.Cache
|
||||
|
||||
const val EMOJI_SUGGESTION_INDICATOR = ':'
|
||||
const val EMOJI_SUGGESTION_MAX_COUNT = 5
|
||||
private const val EMOJI_SUGGESTION_QUERY_MIN_LENGTH = 3
|
||||
|
||||
/**
|
||||
* Provides emoji suggestions within a text input context.
|
||||
*
|
||||
@@ -30,7 +42,7 @@ class EmojiSuggestionProvider(private val context: Context) : SuggestionProvider
|
||||
override val providerId = "org.florisboard.nlp.providers.emoji"
|
||||
|
||||
private val prefs by florisPreferenceModel()
|
||||
private val lettersRegex = "^:[A-Za-z]*$".toRegex()
|
||||
private val lettersRegex = "^[A-Za-z]*$".toRegex()
|
||||
|
||||
private val cachedEmojiMappings = Cache.Builder().build<FlorisLocale, EmojiDataBySkinTone>()
|
||||
|
||||
@@ -52,7 +64,8 @@ class EmojiSuggestionProvider(private val context: Context) : SuggestionProvider
|
||||
allowPossiblyOffensive: Boolean,
|
||||
isPrivateSession: Boolean
|
||||
): List<SuggestionCandidate> {
|
||||
val preferredSkinTone = prefs.media.emojiPreferredSkinTone.get()
|
||||
val preferredSkinTone = prefs.emoji.preferredSkinTone.get()
|
||||
val showName = prefs.emoji.suggestionCandidateShowName.get()
|
||||
val query = validateInputQuery(content.composingText) ?: return emptyList()
|
||||
val emojis = cachedEmojiMappings.get(subtype.primaryLocale)?.get(preferredSkinTone) ?: emptyList()
|
||||
val candidates = withContext(Dispatchers.Default) {
|
||||
@@ -62,14 +75,24 @@ class EmojiSuggestionProvider(private val context: Context) : SuggestionProvider
|
||||
emoji.keywords.any { it.contains(query, ignoreCase = true) }
|
||||
}
|
||||
.limit(maxCandidateCount.toLong())
|
||||
.map { EmojiSuggestionCandidate(it) }
|
||||
.map { emoji ->
|
||||
EmojiSuggestionCandidate(
|
||||
emoji = emoji,
|
||||
showName = showName,
|
||||
sourceProvider = this@EmojiSuggestionProvider,
|
||||
)
|
||||
}
|
||||
.collect(Collectors.toList())
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
override suspend fun notifySuggestionAccepted(subtype: Subtype, candidate: SuggestionCandidate) {
|
||||
// No-op
|
||||
val updateHistory = prefs.emoji.suggestionUpdateHistory.get()
|
||||
if (!updateHistory || candidate !is EmojiSuggestionCandidate) {
|
||||
return
|
||||
}
|
||||
EmojiHistoryHelper.markEmojiUsed(prefs, candidate.emoji)
|
||||
}
|
||||
|
||||
override suspend fun notifySuggestionReverted(subtype: Subtype, candidate: SuggestionCandidate) {
|
||||
@@ -90,15 +113,18 @@ class EmojiSuggestionProvider(private val context: Context) : SuggestionProvider
|
||||
* Validates the user input query for emoji suggestions.
|
||||
*/
|
||||
private fun validateInputQuery(composingText: CharSequence): String? {
|
||||
if (!composingText.startsWith(EMOJI_SUGGESTION_INDICATOR)) {
|
||||
val prefix = prefs.emoji.suggestionType.get().prefix
|
||||
val queryMinLength = prefs.emoji.suggestionQueryMinLength.get() + prefix.length
|
||||
if (prefix.isNotEmpty() && !composingText.startsWith(prefix)) {
|
||||
return null
|
||||
}
|
||||
if (composingText.length <= EMOJI_SUGGESTION_QUERY_MIN_LENGTH) {
|
||||
if (composingText.length < queryMinLength) {
|
||||
return null
|
||||
}
|
||||
if (!lettersRegex.matches(composingText)) {
|
||||
val emojiPartialName = composingText.substring(prefix.length)
|
||||
if (!lettersRegex.matches(emojiPartialName)) {
|
||||
return null
|
||||
}
|
||||
return composingText.substring(1)
|
||||
return emojiPartialName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.media.emoji
|
||||
|
||||
enum class EmojiSuggestionType(val prefix: String) {
|
||||
LEADING_COLON(":"),
|
||||
INLINE_TEXT(""),
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.nlp
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Size
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InlineSuggestion
|
||||
import android.view.inputmethod.InlineSuggestionInfo
|
||||
import android.widget.inline.InlineContentView
|
||||
import androidx.annotation.RequiresApi
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogInfo
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogWarning
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
data class NlpInlineAutofillSuggestion(
|
||||
val info: InlineSuggestionInfo,
|
||||
val view: InlineContentView?,
|
||||
)
|
||||
|
||||
object NlpInlineAutofill {
|
||||
private val currentSequenceId = AtomicInteger(0)
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
|
||||
private val setterGuard = Mutex()
|
||||
private val _suggestions = MutableStateFlow<List<NlpInlineAutofillSuggestion>>(emptyList())
|
||||
val suggestions = _suggestions
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
fun showInlineSuggestions(context: Context, rawSuggestions: List<InlineSuggestion>): Boolean {
|
||||
val sequenceId = generateSequenceId()
|
||||
|
||||
if (rawSuggestions.isEmpty()) {
|
||||
clearInlineSuggestions(sequenceId)
|
||||
return false
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
val size = Size(ViewGroup.LayoutParams.WRAP_CONTENT, FlorisImeSizing.Static.smartbarHeightPx)
|
||||
val latch = CountDownLatch(rawSuggestions.size)
|
||||
val suggestionsArray = Array<NlpInlineAutofillSuggestion?>(rawSuggestions.size) { null }
|
||||
|
||||
flogInfo { "showInlineSuggestions: [${sequenceId}] start inflating suggestions" }
|
||||
for ((index, rawSuggestion) in rawSuggestions.withIndex()) {
|
||||
rawSuggestion.inflate(context, size, context.mainExecutor) { view ->
|
||||
suggestionsArray[index] = NlpInlineAutofillSuggestion(rawSuggestion.info, view)
|
||||
latch.countDown()
|
||||
}
|
||||
}
|
||||
|
||||
if (!latch.await(2_000, TimeUnit.MILLISECONDS)) {
|
||||
flogWarning { "showInlineSuggestions: [${sequenceId}] timed out while waiting for all " +
|
||||
"suggestions to inflate" }
|
||||
return@launch
|
||||
}
|
||||
|
||||
val suggestions = suggestionsArray.filterNotNull().sortedByDescending { it.info.isPinned }
|
||||
setterGuard.lock()
|
||||
flogInfo { "showInlineSuggestions: [${sequenceId}] successfully inflated " +
|
||||
"${suggestions.count { it.view != null }} out of ${suggestions.size} suggestions" }
|
||||
if (currentSequenceId.get() == sequenceId) {
|
||||
flogInfo { "showInlineSuggestions: [${sequenceId}] setting suggestions" }
|
||||
_suggestions.value = suggestions
|
||||
} else {
|
||||
flogWarning { "showInlineSuggestions: [${sequenceId}] seqId != current, skip setting suggestions" }
|
||||
}
|
||||
setterGuard.unlock()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun clearInlineSuggestions() {
|
||||
// Increment sequence id to invalidate eventual pending suggestions
|
||||
clearInlineSuggestions(generateSequenceId())
|
||||
}
|
||||
|
||||
private fun clearInlineSuggestions(sequenceId: Int) {
|
||||
scope.launch {
|
||||
setterGuard.lock()
|
||||
flogInfo { "clearInlineSuggestions: [${sequenceId}] clearing suggestions" }
|
||||
_suggestions.value = emptyList()
|
||||
setterGuard.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSequenceId(): Int {
|
||||
return currentSequenceId.incrementAndGet()
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,8 @@
|
||||
package dev.patrickgold.florisboard.ime.nlp
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.SystemClock
|
||||
import android.util.LruCache
|
||||
import android.util.Size
|
||||
import android.view.inputmethod.InlineSuggestion
|
||||
import android.widget.inline.InlineContentView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.clipboardManager
|
||||
@@ -34,12 +28,10 @@ import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorContent
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorRange
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EMOJI_SUGGESTION_MAX_COUNT
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSuggestionProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.han.HanShapeBasedLanguageProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.latin.LatinLanguageProvider
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||
import dev.patrickgold.florisboard.lib.util.NetworkUtils
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -53,7 +45,6 @@ import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
import org.florisboard.lib.kotlin.guardedByLock
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.properties.Delegates
|
||||
@@ -70,7 +61,7 @@ class NlpManager(context: Context) {
|
||||
private val subtypeManager by context.subtypeManager()
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
|
||||
private val clipboardSuggestionProvider = ClipboardSuggestionProvider()
|
||||
private val clipboardSuggestionProvider = ClipboardSuggestionProvider(context)
|
||||
private val emojiSuggestionProvider = EmojiSuggestionProvider(context)
|
||||
private val providers = guardedByLock {
|
||||
mapOf(
|
||||
@@ -94,10 +85,6 @@ class NlpManager(context: Context) {
|
||||
_activeCandidatesFlow.value = v
|
||||
}
|
||||
|
||||
private val inlineContentViews = Collections.synchronizedMap<InlineSuggestion, InlineContentView>(hashMapOf())
|
||||
private val _inlineSuggestions = MutableLiveData<List<InlineSuggestion>>(emptyList())
|
||||
val inlineSuggestions: LiveData<List<InlineSuggestion>> get() = _inlineSuggestions
|
||||
|
||||
val debugOverlaySuggestionsInfos = LruCache<Long, Pair<String, SpellingResult>>(10)
|
||||
var debugOverlayVersion = MutableLiveData(0)
|
||||
private val debugOverlayVersionSource = AtomicInteger(0)
|
||||
@@ -112,6 +99,9 @@ class NlpManager(context: Context) {
|
||||
prefs.suggestion.clipboardContentEnabled.observeForever {
|
||||
assembleCandidates()
|
||||
}
|
||||
prefs.emoji.suggestionEnabled.observeForever {
|
||||
assembleCandidates()
|
||||
}
|
||||
subtypeManager.activeSubtypeFlow.collectLatestIn(scope) { subtype ->
|
||||
preload(subtype)
|
||||
}
|
||||
@@ -202,21 +192,45 @@ class NlpManager(context: Context) {
|
||||
}
|
||||
|
||||
fun isSuggestionOn(): Boolean =
|
||||
prefs.suggestion.enabled.get() || providerForcesSuggestionOn(subtypeManager.activeSubtype)
|
||||
prefs.suggestion.enabled.get()
|
||||
|| prefs.emoji.suggestionEnabled.get()
|
||||
|| providerForcesSuggestionOn(subtypeManager.activeSubtype)
|
||||
|
||||
fun suggest(subtype: Subtype, content: EditorContent) {
|
||||
val reqTime = SystemClock.uptimeMillis()
|
||||
scope.launch {
|
||||
val suggestions = getSuggestionProvider(subtype).suggest(
|
||||
subtype = subtype,
|
||||
content = content,
|
||||
maxCandidateCount = 8,
|
||||
allowPossiblyOffensive = !prefs.suggestion.blockPossiblyOffensive.get(),
|
||||
isPrivateSession = keyboardManager.activeState.isIncognitoMode,
|
||||
)
|
||||
val emojiSuggestions = when {
|
||||
prefs.emoji.suggestionEnabled.get() -> {
|
||||
emojiSuggestionProvider.suggest(
|
||||
subtype = subtype,
|
||||
content = content,
|
||||
maxCandidateCount = prefs.emoji.suggestionCandidateMaxCount.get(),
|
||||
allowPossiblyOffensive = !prefs.suggestion.blockPossiblyOffensive.get(),
|
||||
isPrivateSession = keyboardManager.activeState.isIncognitoMode,
|
||||
)
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
val suggestions = when {
|
||||
emojiSuggestions.isNotEmpty() && prefs.emoji.suggestionType.get().prefix.isNotEmpty() -> {
|
||||
emptyList()
|
||||
}
|
||||
else -> {
|
||||
getSuggestionProvider(subtype).suggest(
|
||||
subtype = subtype,
|
||||
content = content,
|
||||
maxCandidateCount = 8,
|
||||
allowPossiblyOffensive = !prefs.suggestion.blockPossiblyOffensive.get(),
|
||||
isPrivateSession = keyboardManager.activeState.isIncognitoMode,
|
||||
)
|
||||
}
|
||||
}
|
||||
internalSuggestionsGuard.withLock {
|
||||
if (internalSuggestions.first < reqTime) {
|
||||
internalSuggestions = reqTime to suggestions
|
||||
internalSuggestions = reqTime to buildList {
|
||||
addAll(emojiSuggestions)
|
||||
addAll(suggestions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,24 +281,16 @@ class NlpManager(context: Context) {
|
||||
runBlocking {
|
||||
val candidates = when {
|
||||
isSuggestionOn() -> {
|
||||
emojiSuggestionProvider.suggest(
|
||||
subtype = subtypeManager.activeSubtype,
|
||||
clipboardSuggestionProvider.suggest(
|
||||
subtype = Subtype.DEFAULT,
|
||||
content = editorInstance.activeContent,
|
||||
maxCandidateCount = EMOJI_SUGGESTION_MAX_COUNT,
|
||||
maxCandidateCount = 8,
|
||||
allowPossiblyOffensive = !prefs.suggestion.blockPossiblyOffensive.get(),
|
||||
isPrivateSession = keyboardManager.activeState.isIncognitoMode,
|
||||
).ifEmpty {
|
||||
clipboardSuggestionProvider.suggest(
|
||||
subtype = Subtype.DEFAULT,
|
||||
content = editorInstance.activeContent,
|
||||
maxCandidateCount = 8,
|
||||
allowPossiblyOffensive = !prefs.suggestion.blockPossiblyOffensive.get(),
|
||||
isPrivateSession = keyboardManager.activeState.isIncognitoMode,
|
||||
).ifEmpty {
|
||||
buildList {
|
||||
internalSuggestionsGuard.withLock {
|
||||
addAll(internalSuggestions.second)
|
||||
}
|
||||
buildList {
|
||||
internalSuggestionsGuard.withLock {
|
||||
addAll(internalSuggestions.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,68 +298,27 @@ class NlpManager(context: Context) {
|
||||
else -> emptyList()
|
||||
}
|
||||
activeCandidates = candidates
|
||||
autoExpandCollapseSmartbarActions(candidates, inlineSuggestions.value)
|
||||
autoExpandCollapseSmartbarActions(candidates, NlpInlineAutofill.suggestions.value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflates the given inline suggestions. Once all provided views are ready, the suggestions
|
||||
* strip is updated and the Smartbar update cycle is triggered.
|
||||
*
|
||||
* @param inlineSuggestions A collection of inline suggestions to be inflated and shown.
|
||||
*/
|
||||
fun showInlineSuggestions(inlineSuggestions: List<InlineSuggestion>) {
|
||||
inlineContentViews.clear()
|
||||
_inlineSuggestions.postValue(inlineSuggestions)
|
||||
autoExpandCollapseSmartbarActions(activeCandidates, inlineSuggestions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the inline suggestions and triggers the Smartbar update cycle.
|
||||
*/
|
||||
fun clearInlineSuggestions() {
|
||||
inlineContentViews.clear()
|
||||
_inlineSuggestions.postValue(emptyList())
|
||||
autoExpandCollapseSmartbarActions(activeCandidates, null)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
fun inflateOrGet(
|
||||
context: Context,
|
||||
size: Size,
|
||||
inlineSuggestion: InlineSuggestion,
|
||||
callback: (InlineContentView) -> Unit,
|
||||
) {
|
||||
val view = inlineContentViews[inlineSuggestion]
|
||||
if (view != null) {
|
||||
callback(view)
|
||||
} else {
|
||||
try {
|
||||
inlineSuggestion.inflate(context, size, context.mainExecutor) { inflatedView ->
|
||||
if (inflatedView != null) {
|
||||
inlineContentViews[inlineSuggestion] = inflatedView
|
||||
callback(inflatedView)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
flogError { e.toString() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun autoExpandCollapseSmartbarActions(list1: List<*>?, list2: List<*>?) {
|
||||
if (prefs.smartbar.enabled.get() && prefs.smartbar.sharedActionsAutoExpandCollapse.get()) {
|
||||
if (keyboardManager.inputEventDispatcher.isRepeatableCodeLastDown()
|
||||
|| keyboardManager.activeState.isActionsOverflowVisible
|
||||
) {
|
||||
return // We do not auto switch if a repeatable action key was last pressed or if the actions overflow
|
||||
// menu is visible to prevent annoying UI changes
|
||||
}
|
||||
val isSelection = editorInstance.activeContent.selection.isSelectionMode
|
||||
val isExpanded = list1.isNullOrEmpty() && list2.isNullOrEmpty() || isSelection
|
||||
prefs.smartbar.sharedActionsExpandWithAnimation.set(false)
|
||||
prefs.smartbar.sharedActionsExpanded.set(isExpanded)
|
||||
fun autoExpandCollapseSmartbarActions(list1: List<*>?, list2: List<*>?) {
|
||||
if (!prefs.smartbar.enabled.get()) {// || !prefs.smartbar.sharedActionsAutoExpandCollapse.get()) {
|
||||
return
|
||||
}
|
||||
// TODO: this is a mess and needs to be cleaned up in v0.5 with the NLP development
|
||||
/*if (keyboardManager.inputEventDispatcher.isRepeatableCodeLastDown()
|
||||
&& !keyboardManager.inputEventDispatcher.isPressed(KeyCode.DELETE)
|
||||
&& !keyboardManager.inputEventDispatcher.isPressed(KeyCode.FORWARD_DELETE)
|
||||
|| keyboardManager.activeState.isActionsOverflowVisible
|
||||
) {
|
||||
return // We do not auto switch if a repeatable action key was last pressed or if the actions overflow
|
||||
// menu is visible to prevent annoying UI changes
|
||||
}*/
|
||||
val isSelection = editorInstance.activeContent.selection.isSelectionMode
|
||||
val isExpanded = list1.isNullOrEmpty() && list2.isNullOrEmpty() || isSelection
|
||||
prefs.smartbar.sharedActionsExpandWithAnimation.set(false)
|
||||
prefs.smartbar.sharedActionsExpanded.set(isExpanded)
|
||||
}
|
||||
|
||||
fun addToDebugOverlay(word: String, info: SpellingResult) {
|
||||
@@ -384,7 +349,7 @@ class NlpManager(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
inner class ClipboardSuggestionProvider internal constructor() : SuggestionProvider {
|
||||
inner class ClipboardSuggestionProvider internal constructor(private val context: Context) : SuggestionProvider {
|
||||
private var lastClipboardItemId: Long = -1
|
||||
|
||||
override val providerId = "org.florisboard.nlp.providers.clipboard"
|
||||
@@ -413,7 +378,10 @@ class NlpManager(context: Context) {
|
||||
return buildList {
|
||||
val now = System.currentTimeMillis()
|
||||
if ((now - currentItem.creationTimestampMs) < prefs.suggestion.clipboardContentTimeout.get() * 1000) {
|
||||
add(ClipboardSuggestionCandidate(currentItem, sourceProvider = this@ClipboardSuggestionProvider))
|
||||
add(ClipboardSuggestionCandidate(currentItem, sourceProvider = this@ClipboardSuggestionProvider, context = context))
|
||||
if (currentItem.isSensitive) {
|
||||
return@buildList
|
||||
}
|
||||
if (currentItem.type == ItemType.TEXT) {
|
||||
val text = currentItem.stringRepresentation()
|
||||
val matches = buildList {
|
||||
@@ -437,6 +405,7 @@ class NlpManager(context: Context) {
|
||||
}
|
||||
),
|
||||
sourceProvider = this@ClipboardSuggestionProvider,
|
||||
context = context,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.icu.text.BreakIterator
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorContent
|
||||
import dev.patrickgold.florisboard.ime.editor.EditorRange
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EMOJI_SUGGESTION_INDICATOR
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.EmojiSuggestionType
|
||||
|
||||
/**
|
||||
* Base interface for any NLP provider implementation. NLP providers maintain their own internal state and only receive
|
||||
@@ -221,7 +221,7 @@ interface SuggestionProvider : NlpProvider {
|
||||
// Include Emoji indicator in local composing. This is required so that emoji suggestion indicator'
|
||||
// can be detected in the composing text.
|
||||
(pos - 1).takeIf { updatedPos ->
|
||||
textBeforeSelection.getOrNull(updatedPos) == EMOJI_SUGGESTION_INDICATOR
|
||||
textBeforeSelection.getOrNull(updatedPos) == EmojiSuggestionType.LEADING_COLON.prefix.first()
|
||||
} ?: pos
|
||||
}
|
||||
EditorRange(start, end)
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.nlp
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.Assignment
|
||||
import androidx.compose.material.icons.filled.Email
|
||||
import androidx.compose.material.icons.filled.Image
|
||||
import androidx.compose.material.icons.filled.Link
|
||||
import androidx.compose.material.icons.filled.Phone
|
||||
import androidx.compose.material.icons.filled.Videocam
|
||||
import androidx.compose.material.icons.outlined.Assignment
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardItem
|
||||
import dev.patrickgold.florisboard.ime.clipboard.provider.ItemType
|
||||
@@ -123,8 +124,9 @@ data class WordSuggestionCandidate(
|
||||
data class ClipboardSuggestionCandidate(
|
||||
val clipboardItem: ClipboardItem,
|
||||
override val sourceProvider: SuggestionProvider?,
|
||||
val context: Context,
|
||||
) : SuggestionCandidate {
|
||||
override val text: CharSequence = clipboardItem.stringRepresentation()
|
||||
override val text: CharSequence = clipboardItem.displayText(context)
|
||||
|
||||
override val secondaryText: CharSequence? = null
|
||||
|
||||
@@ -139,7 +141,7 @@ data class ClipboardSuggestionCandidate(
|
||||
NetworkUtils.isEmailAddress(text) -> Icons.Default.Email
|
||||
NetworkUtils.isUrl(text) -> Icons.Default.Link
|
||||
NetworkUtils.isPhoneNumber(text) -> Icons.Default.Phone
|
||||
else -> Icons.Outlined.Assignment
|
||||
else -> Icons.AutoMirrored.Outlined.Assignment
|
||||
}
|
||||
ItemType.IMAGE -> Icons.Default.Image
|
||||
ItemType.VIDEO -> Icons.Default.Videocam
|
||||
@@ -157,6 +159,7 @@ data class ClipboardSuggestionCandidate(
|
||||
*/
|
||||
data class EmojiSuggestionCandidate(
|
||||
val emoji: Emoji,
|
||||
val showName: Boolean,
|
||||
override val confidence: Double = 1.0,
|
||||
override val isEligibleForAutoCommit: Boolean = false,
|
||||
override val isEligibleForUserRemoval: Boolean = false,
|
||||
@@ -164,5 +167,5 @@ data class EmojiSuggestionCandidate(
|
||||
override val sourceProvider: SuggestionProvider? = null,
|
||||
) : SuggestionCandidate {
|
||||
override val text = emoji.value
|
||||
override val secondaryText = emoji.name
|
||||
override val secondaryText = if (showName) emoji.name else null
|
||||
}
|
||||
|
||||
@@ -24,14 +24,13 @@ import dev.patrickgold.florisboard.ime.nlp.SpellingProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.SpellingResult
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionCandidate
|
||||
import dev.patrickgold.florisboard.ime.nlp.SuggestionProvider
|
||||
import dev.patrickgold.florisboard.ime.nlp.WordSuggestionCandidate
|
||||
import org.florisboard.lib.android.readText
|
||||
import dev.patrickgold.florisboard.lib.devtools.flogDebug
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.builtins.MapSerializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.florisboard.lib.android.readText
|
||||
import org.florisboard.lib.kotlin.guardedByLock
|
||||
|
||||
class LatinLanguageProvider(context: Context) : SpellingProvider, SuggestionProvider {
|
||||
@@ -106,7 +105,8 @@ class LatinLanguageProvider(context: Context) : SpellingProvider, SuggestionProv
|
||||
allowPossiblyOffensive: Boolean,
|
||||
isPrivateSession: Boolean,
|
||||
): List<SuggestionCandidate> {
|
||||
val word = content.composingText.ifBlank { "next" }
|
||||
return emptyList()
|
||||
/*val word = content.composingText.ifBlank { "next" }
|
||||
val suggestions = buildList {
|
||||
for (n in 0 until maxCandidateCount) {
|
||||
add(WordSuggestionCandidate(
|
||||
@@ -119,7 +119,7 @@ class LatinLanguageProvider(context: Context) : SpellingProvider, SuggestionProv
|
||||
))
|
||||
}
|
||||
}
|
||||
return suggestions
|
||||
return suggestions*/
|
||||
}
|
||||
|
||||
override suspend fun notifySuggestionAccepted(subtype: Subtype, candidate: SuggestionCandidate) {
|
||||
|
||||
@@ -22,8 +22,8 @@ import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.ZoomOutMap
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -81,9 +81,9 @@ fun RowScope.OneHandedPanel(
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (panelSide == OneHandedMode.START) {
|
||||
Icons.Default.KeyboardArrowLeft
|
||||
Icons.AutoMirrored.Filled.KeyboardArrowLeft
|
||||
} else {
|
||||
Icons.Default.KeyboardArrowRight
|
||||
Icons.AutoMirrored.Filled.KeyboardArrowRight
|
||||
},
|
||||
contentDescription = stringRes(
|
||||
if (panelSide == OneHandedMode.START) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Patrick Goldinger
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,16 +58,14 @@ import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.conditional
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.compose.safeTimes
|
||||
import dev.patrickgold.florisboard.lib.observeAsNonNullState
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.solidColor
|
||||
import org.florisboard.lib.snygg.ui.spSize
|
||||
|
||||
private val CandidatesRowScrollbarHeight = 2.dp
|
||||
val CandidatesRowScrollbarHeight = 2.dp
|
||||
|
||||
@Composable
|
||||
fun CandidatesRow(modifier: Modifier = Modifier) {
|
||||
@@ -79,84 +77,71 @@ fun CandidatesRow(modifier: Modifier = Modifier) {
|
||||
|
||||
val displayMode by prefs.suggestion.displayMode.observeAsState()
|
||||
val candidates by nlpManager.activeCandidatesFlow.collectAsState()
|
||||
val inlineSuggestions by nlpManager.inlineSuggestions.observeAsNonNullState()
|
||||
|
||||
val rowStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarCandidatesRow)
|
||||
val spacerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarCandidateSpacer)
|
||||
|
||||
if (AndroidVersion.ATLEAST_API30_R && inlineSuggestions.isNotEmpty()) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.florisHorizontalScroll(scrollbarHeight = CandidatesRowScrollbarHeight),
|
||||
) {
|
||||
for (inlineSuggestion in inlineSuggestions) {
|
||||
InlineSuggestionView(inlineSuggestion = inlineSuggestion)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.snyggBackground(context, rowStyle)
|
||||
.conditional(displayMode == CandidatesDisplayMode.DYNAMIC_SCROLLABLE && candidates.size > 1) {
|
||||
florisHorizontalScroll(scrollbarHeight = CandidatesRowScrollbarHeight)
|
||||
},
|
||||
horizontalArrangement = if (candidates.size > 1) {
|
||||
Arrangement.Start
|
||||
} else {
|
||||
Arrangement.Center
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.snyggBackground(context, rowStyle)
|
||||
.conditional(displayMode == CandidatesDisplayMode.DYNAMIC_SCROLLABLE && candidates.size > 1) {
|
||||
florisHorizontalScroll(scrollbarHeight = CandidatesRowScrollbarHeight)
|
||||
},
|
||||
) {
|
||||
if (candidates.isNotEmpty()) {
|
||||
val candidateModifier = if (candidates.size == 1) {
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f, fill = false)
|
||||
} else {
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.conditional(displayMode == CandidatesDisplayMode.CLASSIC) {
|
||||
weight(1f)
|
||||
}
|
||||
.conditional(displayMode != CandidatesDisplayMode.CLASSIC) {
|
||||
wrapContentWidth().widthIn(max = 160.dp)
|
||||
}
|
||||
}
|
||||
val list = when (displayMode) {
|
||||
CandidatesDisplayMode.CLASSIC -> candidates.subList(0, 3.coerceAtMost(candidates.size))
|
||||
else -> candidates
|
||||
}
|
||||
for ((n, candidate) in list.withIndex()) {
|
||||
if (n > 0) {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.fillMaxHeight(0.6f)
|
||||
.align(Alignment.CenterVertically)
|
||||
.snyggBackground(context, spacerStyle),
|
||||
)
|
||||
horizontalArrangement = if (candidates.size > 1) {
|
||||
Arrangement.Start
|
||||
} else {
|
||||
Arrangement.Center
|
||||
},
|
||||
) {
|
||||
if (candidates.isNotEmpty()) {
|
||||
val candidateModifier = if (candidates.size == 1) {
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(1f, fill = false)
|
||||
} else {
|
||||
Modifier
|
||||
.fillMaxHeight()
|
||||
.conditional(displayMode == CandidatesDisplayMode.CLASSIC) {
|
||||
weight(1f)
|
||||
}
|
||||
CandidateItem(
|
||||
modifier = candidateModifier,
|
||||
candidate = candidate,
|
||||
displayMode = displayMode,
|
||||
onClick = {
|
||||
// Can't use candidate directly
|
||||
keyboardManager.commitCandidate(candidates[n])
|
||||
},
|
||||
onLongPress = {
|
||||
// Can't use candidate directly
|
||||
val candidateItem = candidates[n]
|
||||
if (candidateItem.isEligibleForUserRemoval) {
|
||||
nlpManager.removeSuggestion(subtypeManager.activeSubtype, candidateItem)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
longPressDelay = prefs.keyboard.longPressDelay.get().toLong(),
|
||||
.conditional(displayMode != CandidatesDisplayMode.CLASSIC) {
|
||||
wrapContentWidth().widthIn(max = 160.dp)
|
||||
}
|
||||
}
|
||||
val list = when (displayMode) {
|
||||
CandidatesDisplayMode.CLASSIC -> candidates.subList(0, 3.coerceAtMost(candidates.size))
|
||||
else -> candidates
|
||||
}
|
||||
for ((n, candidate) in list.withIndex()) {
|
||||
if (n > 0) {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.fillMaxHeight(0.6f)
|
||||
.align(Alignment.CenterVertically)
|
||||
.snyggBackground(context, spacerStyle),
|
||||
)
|
||||
}
|
||||
CandidateItem(
|
||||
modifier = candidateModifier,
|
||||
candidate = candidate,
|
||||
displayMode = displayMode,
|
||||
onClick = {
|
||||
// Can't use candidate directly
|
||||
keyboardManager.commitCandidate(candidates[n])
|
||||
},
|
||||
onLongPress = {
|
||||
// Can't use candidate directly
|
||||
val candidateItem = candidates[n]
|
||||
if (candidateItem.isEligibleForUserRemoval) {
|
||||
nlpManager.removeSuggestion(subtypeManager.activeSubtype, candidateItem)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
longPressDelay = prefs.keyboard.longPressDelay.get().toLong(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.smartbar
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Size
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InlineSuggestion
|
||||
import android.widget.inline.InlineContentView
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@Composable
|
||||
fun InlineSuggestionView(inlineSuggestion: InlineSuggestion) = with(LocalDensity.current) {
|
||||
val context = LocalContext.current
|
||||
val nlpManager by context.nlpManager()
|
||||
|
||||
val size = Size(ViewGroup.LayoutParams.WRAP_CONTENT, FlorisImeSizing.smartbarHeight.toPx().toInt())
|
||||
var inlineContentView by remember { mutableStateOf<InlineContentView?>(null) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
nlpManager.inflateOrGet(context, size, inlineSuggestion) { view ->
|
||||
inlineContentView = view
|
||||
}
|
||||
}
|
||||
|
||||
if (inlineContentView != null) {
|
||||
AndroidView(
|
||||
factory = { inlineContentView!! },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* 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.smartbar
|
||||
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInParent
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofillSuggestion
|
||||
import dev.patrickgold.florisboard.lib.compose.florisHorizontalScroll
|
||||
import dev.patrickgold.florisboard.lib.toIntOffset
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
@Composable
|
||||
fun InlineSuggestionsUi(
|
||||
inlineSuggestions: List<NlpInlineAutofillSuggestion>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
val almostEmptyRect = remember { android.graphics.Rect(0, 0, 1, 1) }
|
||||
|
||||
Row(
|
||||
modifier
|
||||
.fillMaxSize()
|
||||
.florisHorizontalScroll(
|
||||
state = scrollState,
|
||||
scrollbarHeight = CandidatesRowScrollbarHeight,
|
||||
),
|
||||
) {
|
||||
val xMin = scrollState.value
|
||||
val xMax = scrollState.value + scrollState.viewportSize
|
||||
for (inlineSuggestion in inlineSuggestions) {
|
||||
if (inlineSuggestion.view == null) {
|
||||
continue
|
||||
}
|
||||
var chipPos by remember { mutableStateOf(IntOffset.Zero) }
|
||||
AndroidView(
|
||||
modifier = Modifier.onGloballyPositioned { chipPos = it.positionInParent().toIntOffset() },
|
||||
factory = { inlineSuggestion.view },
|
||||
update = { view ->
|
||||
view.clipBounds = android.graphics.Rect(
|
||||
(xMin - chipPos.x).coerceAtLeast(0),
|
||||
0,
|
||||
(xMax - chipPos.x).coerceAtMost(view.width),
|
||||
view.height,
|
||||
)
|
||||
// The empty rect is a workaround for a bug (I suppose) where an empty rect causes
|
||||
// no clipping, but we actually want to completely hide the view.
|
||||
// Thus we just show the topmost pixel of the view, which due to the round shape
|
||||
// of the theme should be transparent anyways.
|
||||
if (view.clipBounds.isEmpty) {
|
||||
view.clipBounds = almostEmptyRect
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import androidx.compose.material.icons.filled.UnfoldMore
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -56,6 +57,7 @@ import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.keyboard.FlorisImeSizing
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpInlineAutofill
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionButton
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionsRow
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.ToggleOverflowPanelAction
|
||||
@@ -64,8 +66,10 @@ import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.keyboardManager
|
||||
import dev.patrickgold.florisboard.lib.compose.horizontalTween
|
||||
import dev.patrickgold.florisboard.lib.compose.verticalTween
|
||||
import dev.patrickgold.florisboard.nlpManager
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import dev.patrickgold.jetpref.datastore.ui.vectorResource
|
||||
import org.florisboard.lib.android.AndroidVersion
|
||||
import org.florisboard.lib.snygg.ui.snyggBackground
|
||||
import org.florisboard.lib.snygg.ui.snyggBorder
|
||||
import org.florisboard.lib.snygg.ui.snyggShadow
|
||||
@@ -138,6 +142,13 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val nlpManager by context.nlpManager()
|
||||
|
||||
val inlineSuggestions by NlpInlineAutofill.suggestions.collectAsState()
|
||||
LaunchedEffect(inlineSuggestions) {
|
||||
nlpManager.autoExpandCollapseSmartbarActions(null, inlineSuggestions)
|
||||
}
|
||||
val shouldShowInlineSuggestionsUi = AndroidVersion.ATLEAST_API30_R && inlineSuggestions.isNotEmpty()
|
||||
|
||||
val smartbarLayout by prefs.smartbar.layout.observeAsState()
|
||||
val flipToggles by prefs.smartbar.flipToggles.observeAsState()
|
||||
@@ -223,7 +234,11 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
enter = enterTransition,
|
||||
exit = exitTransition,
|
||||
) {
|
||||
CandidatesRow()
|
||||
if (shouldShowInlineSuggestionsUi) {
|
||||
InlineSuggestionsUi(inlineSuggestions)
|
||||
} else {
|
||||
CandidatesRow()
|
||||
}
|
||||
}
|
||||
androidx.compose.animation.AnimatedVisibility(
|
||||
visible = expanded,
|
||||
@@ -331,11 +346,19 @@ private fun SmartbarMainRow(modifier: Modifier = Modifier) {
|
||||
) {
|
||||
when (smartbarLayout) {
|
||||
SmartbarLayout.SUGGESTIONS_ONLY -> {
|
||||
CandidatesRow()
|
||||
if (shouldShowInlineSuggestionsUi) {
|
||||
InlineSuggestionsUi(inlineSuggestions)
|
||||
} else {
|
||||
CandidatesRow()
|
||||
}
|
||||
}
|
||||
|
||||
SmartbarLayout.ACTIONS_ONLY -> {
|
||||
QuickActionsRow(elementName = FlorisImeUi.SmartbarSharedActionsRow)
|
||||
if (shouldShowInlineSuggestionsUi) {
|
||||
InlineSuggestionsUi(inlineSuggestions)
|
||||
} else {
|
||||
QuickActionsRow(elementName = FlorisImeUi.SmartbarSharedActionsRow)
|
||||
}
|
||||
}
|
||||
|
||||
SmartbarLayout.SUGGESTIONS_ACTIONS_SHARED -> {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.smartbar.quickaction
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -33,7 +32,7 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@@ -76,7 +75,6 @@ private const val ItemNotFound = -1
|
||||
private val NoopAction = QuickAction.InsertKey(TextKeyData(code = KeyCode.NOOP))
|
||||
private val DragMarkerAction = QuickAction.InsertKey(TextKeyData(code = KeyCode.DRAG_MARKER))
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
val prefs by florisPreferenceModel()
|
||||
@@ -105,17 +103,20 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorHeader)
|
||||
val subheaderStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorSubheader)
|
||||
|
||||
fun findItemForOffset(offset: IntOffset): LazyGridItemInfo? {
|
||||
fun findItemForOffsetOrClosestInRow(offset: IntOffset): LazyGridItemInfo? {
|
||||
var closestItemInRow: LazyGridItemInfo? = null
|
||||
// Using manual for loop with indices instead of firstOrNull() because this method gets
|
||||
// called a lot and firstOrNull allocates an iterator for each call
|
||||
for (index in gridState.layoutInfo.visibleItemsInfo.indices) {
|
||||
val item = gridState.layoutInfo.visibleItemsInfo[index]
|
||||
if (offset.x in item.offset.x..(item.offset.x + item.size.width) &&
|
||||
offset.y in item.offset.y..(item.offset.y + item.size.height)) {
|
||||
return item
|
||||
if (offset.y in item.offset.y..(item.offset.y + item.size.height)) {
|
||||
if (offset.x in item.offset.x..(item.offset.x + item.size.width)) {
|
||||
return item
|
||||
}
|
||||
closestItemInRow = item
|
||||
}
|
||||
}
|
||||
return null
|
||||
return closestItemInRow
|
||||
}
|
||||
|
||||
fun indexOfStickyAction(item: LazyGridItemInfo): Int {
|
||||
@@ -158,7 +159,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
}
|
||||
|
||||
fun beginDragGesture(pos: IntOffset) {
|
||||
val item = findItemForOffset(pos) ?: return
|
||||
val item = findItemForOffsetOrClosestInRow(pos) ?: return
|
||||
val stickyActionIndex = indexOfStickyAction(item)
|
||||
val dynamicActionIndex = indexOfDynamicAction(item)
|
||||
val hiddenActionIndex = indexOfHiddenAction(item)
|
||||
@@ -182,7 +183,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
if (activeDragAction == null) return
|
||||
val pos = activeDragPosition + posChange
|
||||
activeDragPosition = pos
|
||||
val item = findItemForOffset(pos) ?: return
|
||||
val item = findItemForOffsetOrClosestInRow(pos) ?: return
|
||||
val stickyActionIndex = indexOfStickyAction(item)
|
||||
val dynamicActionIndex = indexOfDynamicAction(item)
|
||||
val hiddenActionIndex = indexOfHiddenAction(item)
|
||||
@@ -263,7 +264,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
onClick = {
|
||||
keyboardManager.activeState.isActionsEditorVisible = false
|
||||
},
|
||||
icon = Icons.Default.KeyboardArrowLeft,
|
||||
icon = Icons.AutoMirrored.Filled.KeyboardArrowLeft,
|
||||
iconColor = headerStyle.foreground.solidColor(context, default = FlorisImeTheme.fallbackContentColor()),
|
||||
)
|
||||
Text(
|
||||
@@ -299,7 +300,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
}
|
||||
item(key = keyOf(stickyAction)) {
|
||||
QuickActionButton(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
modifier = Modifier.animateItem(),
|
||||
action = stickyAction,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
@@ -314,7 +315,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
}
|
||||
itemsIndexed(dynamicActions, key = { i, a -> keyOf(a) ?: i }) { _, action ->
|
||||
QuickActionButton(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
modifier = Modifier.animateItem(),
|
||||
action = action,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
@@ -329,7 +330,7 @@ fun QuickActionsEditorPanel(modifier: Modifier = Modifier) {
|
||||
}
|
||||
itemsIndexed(hiddenActions, key = { i, a -> keyOf(a) ?: i }) { _, action ->
|
||||
QuickActionButton(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
modifier = Modifier.animateItem(),
|
||||
action = action,
|
||||
evaluator = evaluator,
|
||||
type = QuickActionBarType.STATIC_TILE,
|
||||
|
||||
@@ -19,7 +19,6 @@ package dev.patrickgold.florisboard.ime.text
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -32,7 +31,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardMode
|
||||
@@ -74,7 +72,7 @@ fun TextInputLayout(
|
||||
val indicatorStyle = FlorisImeTheme.style.get(FlorisImeUi.IncognitoModeIndicator)
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.requiredSize(192.dp)
|
||||
.matchParentSize()
|
||||
.align(Alignment.Center),
|
||||
painter = painterResource(R.drawable.ic_incognito),
|
||||
contentDescription = null,
|
||||
|
||||
@@ -220,31 +220,39 @@ fun TextKeyboardLayout(
|
||||
}
|
||||
},
|
||||
) {
|
||||
val keyMarginH by prefs.keyboard.keySpacingHorizontal.observeAsTransformingState { it.dp.toPx() }
|
||||
val keyMarginV by prefs.keyboard.keySpacingVertical.observeAsTransformingState { it.dp.toPx() }
|
||||
val desiredKey = remember { TextKey(data = TextKeyData.UNSPECIFIED) }
|
||||
val keyboardWidth = constraints.maxWidth.toFloat()
|
||||
val keyboardHeight = constraints.maxHeight.toFloat()
|
||||
desiredKey.touchBounds.apply {
|
||||
if (isSmartbarKeyboard) {
|
||||
width = keyboardWidth / 8f
|
||||
height = FlorisImeSizing.smartbarHeight.toPx()
|
||||
} else {
|
||||
width = keyboardWidth / 10f
|
||||
height = when (keyboard.mode) {
|
||||
KeyboardMode.CHARACTERS,
|
||||
KeyboardMode.NUMERIC_ADVANCED,
|
||||
KeyboardMode.SYMBOLS,
|
||||
KeyboardMode.SYMBOLS2 -> {
|
||||
(FlorisImeSizing.keyboardUiHeight() / keyboard.rowCount)
|
||||
.coerceAtMost(FlorisImeSizing.keyboardRowBaseHeight * 1.12f).toPx()
|
||||
val keyMarginH by prefs.keyboard.keySpacingHorizontal.observeAsTransformingState { it.dp.toPx() }
|
||||
val keyMarginV by prefs.keyboard.keySpacingVertical.observeAsTransformingState { it.dp.toPx() }
|
||||
val keyboardRowBaseHeight = FlorisImeSizing.keyboardRowBaseHeight
|
||||
|
||||
val desiredKey = remember(
|
||||
keyboard, isSmartbarKeyboard, keyboardWidth, keyboardHeight, keyMarginH, keyMarginV,
|
||||
keyboardRowBaseHeight
|
||||
) {
|
||||
TextKey(data = TextKeyData.UNSPECIFIED).also { desiredKey ->
|
||||
desiredKey.touchBounds.apply {
|
||||
if (isSmartbarKeyboard) {
|
||||
width = keyboardWidth / 8f
|
||||
height = keyboardHeight
|
||||
} else {
|
||||
width = keyboardWidth / 10f
|
||||
height = when (keyboard.mode) {
|
||||
KeyboardMode.CHARACTERS,
|
||||
KeyboardMode.NUMERIC_ADVANCED,
|
||||
KeyboardMode.SYMBOLS,
|
||||
KeyboardMode.SYMBOLS2 -> {
|
||||
(keyboardHeight / keyboard.rowCount)
|
||||
.coerceAtMost(keyboardRowBaseHeight.toPx() * 1.12f)
|
||||
}
|
||||
else -> keyboardRowBaseHeight.toPx()
|
||||
}
|
||||
}
|
||||
else -> FlorisImeSizing.keyboardRowBaseHeight.toPx()
|
||||
}
|
||||
desiredKey.visibleBounds.applyFrom(desiredKey.touchBounds).deflateBy(keyMarginH, keyMarginV)
|
||||
keyboard.layout(keyboardWidth, keyboardHeight, desiredKey, !isSmartbarKeyboard)
|
||||
}
|
||||
}
|
||||
desiredKey.visibleBounds.applyFrom(desiredKey.touchBounds).deflateBy(keyMarginH, keyMarginV)
|
||||
keyboard.layout(keyboardWidth, keyboardHeight, desiredKey, !isSmartbarKeyboard)
|
||||
|
||||
val fontSizeMultiplier = prefs.keyboard.fontSizeMultiplier()
|
||||
val popupUiController = rememberPopupUiController(
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package dev.patrickgold.florisboard.ime.theme
|
||||
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import dev.patrickgold.florisboard.lib.ext.Extension
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionEditor
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionMeta
|
||||
@@ -41,14 +43,14 @@ class ThemeExtension(
|
||||
override fun edit() = ThemeExtensionEditor(
|
||||
meta = meta,
|
||||
dependencies = dependencies?.toMutableList() ?: mutableListOf(),
|
||||
themes = themes.map { it.edit() }.toMutableList(),
|
||||
themes = mutableStateListOf(*themes.map { it.edit() }.toTypedArray()),
|
||||
)
|
||||
}
|
||||
|
||||
class ThemeExtensionEditor(
|
||||
override var meta: ExtensionMeta,
|
||||
override val dependencies: MutableList<String>,
|
||||
val themes: MutableList<ThemeExtensionComponentEditor>,
|
||||
val themes: SnapshotStateList<ThemeExtensionComponentEditor>,
|
||||
) : ExtensionEditor {
|
||||
|
||||
override fun build() = ThemeExtension(
|
||||
|
||||
@@ -199,70 +199,68 @@ class ThemeManager(context: Context) {
|
||||
context: Context,
|
||||
style: SnyggStylesheet = activeThemeInfo.value?.stylesheet ?: FlorisImeThemeBaseStyle,
|
||||
): Bundle {
|
||||
val chipStyle = style.getStatic(FlorisImeUi.SmartbarSharedActionsToggle)
|
||||
val bgColor = chipStyle.background.solidColor(context)
|
||||
val fgColor = chipStyle.foreground.solidColor(context)
|
||||
val snyggStyle = style.getStatic(FlorisImeUi.SmartbarSharedActionsToggle)
|
||||
val bgColor = snyggStyle.background.solidColor(context)
|
||||
val fgColor = snyggStyle.foreground.solidColor(context)
|
||||
|
||||
val bgDrawableId = androidx.autofill.R.drawable.autofill_inline_suggestion_chip_background
|
||||
val stylesBuilder = UiVersions.newStylesBuilder()
|
||||
val suggestionStyle = InlineSuggestionUi.newStyleBuilder()
|
||||
.setSingleIconChipStyle(
|
||||
ViewStyle.Builder()
|
||||
.setBackground(
|
||||
Icon.createWithResource(context, bgDrawableId).setTint(bgColor.toArgb())
|
||||
)
|
||||
.setPadding(0, 0, 0, 0)
|
||||
.build()
|
||||
val bgDrawable = Icon.createWithResource(context, bgDrawableId).apply {
|
||||
setTint(bgColor.toArgb())
|
||||
}
|
||||
val singleIconChipStyle = ViewStyle.Builder().run {
|
||||
setBackground(bgDrawable)
|
||||
setPadding(0, 0, 0, 0)
|
||||
build()
|
||||
}
|
||||
val chipStyle = ViewStyle.Builder().run {
|
||||
setBackground(bgDrawable)
|
||||
setPadding(
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_start).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_top).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_end).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_bottom).toInt(),
|
||||
)
|
||||
.setChipStyle(
|
||||
ViewStyle.Builder()
|
||||
.setBackground(
|
||||
Icon.createWithResource(context, bgDrawableId).setTint(bgColor.toArgb())
|
||||
)
|
||||
.setPadding(
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_start).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_top).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_end).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_bg_padding_bottom).toInt(),
|
||||
)
|
||||
.build()
|
||||
build()
|
||||
}
|
||||
val iconStyle = ImageViewStyle.Builder().run {
|
||||
setLayoutMargin(0, 0, 0, 0)
|
||||
build()
|
||||
}
|
||||
val titleStyle = TextViewStyle.Builder().run {
|
||||
setLayoutMargin(
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_start).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_top).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_end).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_bottom).toInt(),
|
||||
)
|
||||
.setStartIconStyle(
|
||||
ImageViewStyle.Builder()
|
||||
.setLayoutMargin(0, 0, 0, 0)
|
||||
.build()
|
||||
setTextColor(fgColor.toArgb())
|
||||
setTextSize(16f)
|
||||
build()
|
||||
}
|
||||
val subtitleStyle = TextViewStyle.Builder().run {
|
||||
setLayoutMargin(
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_start).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_top).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_end).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_bottom).toInt(),
|
||||
)
|
||||
.setTitleStyle(
|
||||
TextViewStyle.Builder()
|
||||
.setLayoutMargin(
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_start).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_top).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_end).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_title_margin_bottom).toInt(),
|
||||
)
|
||||
.setTextColor(fgColor.toArgb())
|
||||
.setTextSize(16f)
|
||||
.build()
|
||||
)
|
||||
.setSubtitleStyle(
|
||||
TextViewStyle.Builder()
|
||||
.setLayoutMargin(
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_start).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_top).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_end).toInt(),
|
||||
context.resources.getDimension(R.dimen.suggestion_chip_fg_subtitle_margin_bottom).toInt(),
|
||||
)
|
||||
.setTextColor(ColorUtils.setAlphaComponent(fgColor.toArgb(), 150))
|
||||
.setTextSize(14f)
|
||||
.build()
|
||||
)
|
||||
.setEndIconStyle(
|
||||
ImageViewStyle.Builder()
|
||||
.setLayoutMargin(0, 0, 0, 0)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
stylesBuilder.addStyle(suggestionStyle)
|
||||
return stylesBuilder.build()
|
||||
setTextColor(ColorUtils.setAlphaComponent(fgColor.toArgb(), 150))
|
||||
setTextSize(14f)
|
||||
build()
|
||||
}
|
||||
val suggestionStyle = InlineSuggestionUi.newStyleBuilder().run {
|
||||
setSingleIconChipStyle(singleIconChipStyle)
|
||||
setChipStyle(chipStyle)
|
||||
setStartIconStyle(iconStyle)
|
||||
setEndIconStyle(iconStyle)
|
||||
setTitleStyle(titleStyle)
|
||||
setSubtitleStyle(subtitleStyle)
|
||||
build()
|
||||
}
|
||||
return UiVersions.newStylesBuilder().run {
|
||||
addStyle(suggestionStyle)
|
||||
build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColorFromThemeAttribute(
|
||||
|
||||
@@ -361,10 +361,13 @@ class FlorisLocale private constructor(val base: Locale) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun String.lowercase(locale: FlorisLocale): String = this.lowercase(locale.base)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun String.uppercase(locale: FlorisLocale): String = this.uppercase(locale.base)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun String.titlecase(locale: FlorisLocale = FlorisLocale.ROOT): String {
|
||||
return this.replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale.base) else it.toString() }
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.structuralEqualityPolicy
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceData
|
||||
import dev.patrickgold.jetpref.datastore.model.PreferenceObserver
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.provider.OpenableColumns
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.neverEqualPolicy
|
||||
import androidx.compose.runtime.setValue
|
||||
import dev.patrickgold.florisboard.app.ext.EditorAction
|
||||
import dev.patrickgold.florisboard.app.settings.advanced.Backup
|
||||
@@ -188,7 +187,7 @@ class CacheManager(context: Context) {
|
||||
|
||||
var currentAction by mutableStateOf<EditorAction?>(null)
|
||||
var ext: Extension? = null
|
||||
var editor by mutableStateOf<T?>(null, neverEqualPolicy())
|
||||
var editor by mutableStateOf<T?>(null)
|
||||
var version by mutableIntStateOf(0)
|
||||
|
||||
val isModified get() = version > 0
|
||||
@@ -202,7 +201,6 @@ class CacheManager(context: Context) {
|
||||
inline fun <R> update(block: T.() -> R): R {
|
||||
// Method is designed to only be called when editor has been previously initialized
|
||||
val ret = block(editor!!)
|
||||
editor = editor
|
||||
version++
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package dev.patrickgold.florisboard.lib.compose
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.ripple
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
@@ -32,7 +32,7 @@ fun Modifier.rippleClickable(
|
||||
) = composed {
|
||||
this.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(),
|
||||
indication = ripple(),
|
||||
enabled = enabled,
|
||||
onClickLabel = onClickLabel,
|
||||
role = role,
|
||||
|
||||
@@ -19,9 +19,9 @@ package dev.patrickgold.florisboard.lib.compose
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.NonRestartableComposable
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
|
||||
@Composable
|
||||
@NonRestartableComposable
|
||||
|
||||
@@ -25,9 +25,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -39,15 +37,10 @@ fun FlorisChip(
|
||||
onClick: () -> Unit = { },
|
||||
selected: Boolean = false,
|
||||
enabled: Boolean = true,
|
||||
color: Color = Color.Unspecified,
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
leadingIcons: List<ImageVector> = listOf(),
|
||||
trailingIcons: List<ImageVector> = listOf(),
|
||||
) {
|
||||
val backgroundColor = color.takeOrElse {
|
||||
MaterialTheme.colorScheme.onSurface.copy()
|
||||
}
|
||||
|
||||
InputChip(
|
||||
selected = selected,
|
||||
onClick = onClick,
|
||||
@@ -88,42 +81,4 @@ fun FlorisChip(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/*Surface(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
color = backgroundColor,
|
||||
shape = shape,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 4.dp, horizontal = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
for (leadingIcon in leadingIcons) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp)
|
||||
.size(16.dp),
|
||||
imageVector = leadingIcon,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
for (trailingIcon in trailingIcons) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(start = 8.dp)
|
||||
.size(16.dp),
|
||||
imageVector = trailingIcon,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
@@ -95,7 +95,7 @@ private class FlorisScreenScopeImpl : FlorisScreenScope {
|
||||
FlorisIconButton(
|
||||
onClick = { navController.popBackStack() },
|
||||
modifier = Modifier.autoMirrorForRtl(),
|
||||
icon = Icons.Default.ArrowBack,
|
||||
icon = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.lib.compose
|
||||
|
||||
import androidx.compose.foundation.lazy.grid.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridItemScope
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridScope
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
fun LazyGridScope.header(
|
||||
key: Any? = null,
|
||||
content: @Composable LazyGridItemScope.() -> Unit,
|
||||
) {
|
||||
item(key, span = { GridItemSpan(this.maxLineSpan) }, content = content)
|
||||
}
|
||||
@@ -128,7 +128,7 @@ fun PreviewKeyboardField(
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { focusManager.clearFocus() },
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(autoCorrect = true),
|
||||
keyboardOptions = KeyboardOptions(autoCorrectEnabled = true),
|
||||
singleLine = true,
|
||||
shape = RectangleShape,
|
||||
colors = TextFieldDefaults.colors(
|
||||
|
||||
@@ -6,9 +6,9 @@ import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import org.florisboard.lib.android.AndroidSettingsHelper
|
||||
import org.florisboard.lib.android.SystemSettingsObserver
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ import android.os.Debug
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.app.AppPrefs
|
||||
import org.florisboard.lib.android.systemService
|
||||
import dev.patrickgold.florisboard.lib.titlecase
|
||||
import dev.patrickgold.florisboard.lib.util.TimeUtils
|
||||
import dev.patrickgold.florisboard.lib.util.UnitUtils
|
||||
import org.florisboard.lib.android.systemService
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
@@ -49,6 +49,36 @@ object Devtools {
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDebugLogForGithub(context: Context, prefs: AppPrefs? = null, includeLogcat: Boolean = false): String {
|
||||
return buildString {
|
||||
appendLine("<details>")
|
||||
appendLine("<summary>Detailed info (Debug log header)</summary>")
|
||||
appendLine()
|
||||
appendLine("```")
|
||||
append(generateSystemInfoLog(context))
|
||||
appendLine()
|
||||
append(generateAppInfoLog(context))
|
||||
if (prefs != null) {
|
||||
appendLine()
|
||||
append(generateFeatureConfigLog(prefs))
|
||||
}
|
||||
appendLine()
|
||||
appendLine("```")
|
||||
appendLine("</details>")
|
||||
if (includeLogcat) {
|
||||
appendLine()
|
||||
appendLine("<details>")
|
||||
appendLine("<summary>Debug log content</summary>")
|
||||
appendLine()
|
||||
appendLine("```")
|
||||
append(generateLogcatDump())
|
||||
appendLine()
|
||||
appendLine("```")
|
||||
appendLine("</details>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun generateSystemInfoLog(context: Context, withTitle: Boolean = true): String {
|
||||
return buildString {
|
||||
if (withTitle) appendLine("======= SYSTEM INFO =======")
|
||||
|
||||
@@ -21,9 +21,6 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeExtensionComponent
|
||||
import dev.patrickgold.florisboard.lib.ValidationRule
|
||||
import org.florisboard.lib.snygg.SnyggStylesheet
|
||||
import org.florisboard.lib.snygg.value.SnyggDpShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggPercentShapeValue
|
||||
import org.florisboard.lib.snygg.value.SnyggSolidColorValue
|
||||
import dev.patrickgold.florisboard.lib.validate
|
||||
import org.florisboard.lib.snygg.value.SnyggVarValue
|
||||
|
||||
@@ -157,7 +154,7 @@ object ExtensionValidation {
|
||||
}
|
||||
|
||||
val SnyggSolidColorValue = ValidationRule<String> {
|
||||
forKlass = SnyggSolidColorValue::class
|
||||
forKlass = org.florisboard.lib.snygg.value.SnyggSolidColorValue::class
|
||||
forProperty = "color"
|
||||
validator { input ->
|
||||
val str = input.trim()
|
||||
@@ -172,7 +169,7 @@ object ExtensionValidation {
|
||||
}
|
||||
|
||||
val SnyggDpShapeValue = ValidationRule<String> {
|
||||
forKlass = SnyggDpShapeValue::class
|
||||
forKlass = org.florisboard.lib.snygg.value.SnyggDpShapeValue::class
|
||||
forProperty = "corner"
|
||||
validator { str ->
|
||||
val floatValue = str.toFloatOrNull()
|
||||
@@ -186,7 +183,7 @@ object ExtensionValidation {
|
||||
}
|
||||
|
||||
val SnyggPercentShapeValue = ValidationRule<String> {
|
||||
forKlass = SnyggPercentShapeValue::class
|
||||
forKlass = org.florisboard.lib.snygg.value.SnyggPercentShapeValue::class
|
||||
forProperty = "corner"
|
||||
validator { str ->
|
||||
val intValue = str.toIntOrNull()
|
||||
|
||||
@@ -13,9 +13,24 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">الرموز التعبيرية</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">وجوه تعبيرية</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">كاوموجي</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">الحد الأقصى لحجم السجل للرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">لون الرموز التعبيرية المفضل</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">نوع الشعر المفضل للرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">سجل الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">تمكين سجل الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_history_enabled__summary" comment="Preference summary">الاحتفاظ بالرموز التعبيرية المستخدمة مؤخرًا للوصول السريع</string>
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">تحديث الاستراتيجية (مثبت)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">إستراتيجية التحديث (الأخيرة)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">الحد الأقصى للعناصر التي يجب الاحتفاظ بها</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">اقتراحات الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">تمكين اقتراحات الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">تقديم اقتراحات الرموز التعبيرية أثناء الكتابة</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">نوع التفعيل</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">تحديث سجل الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">قَبُول الرموز التعبيرية المقترحة يضيفها إلى تاريخ الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">عرض اسم الرمز التعبيري</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">تعرض اقتراحات الرموز التعبيرية اسمها جنبًا إلى جنب مع الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">الحد الأدنى لطول الاستعلام</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">الحد الأقصى لعدد المرشحين</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">وجوه تعبيرية و عواطف</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">أشخاص و أجسام</string>
|
||||
@@ -26,10 +41,12 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">أشياء</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">الرموز</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">أعلام</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">لم يتم العثور على رموز تعبيرية مستخدمة مؤخرًا. بمجرد أن تبدأ في استخدامها الرموز التعبيرية فإنها ستظهر تلقائيًا هنا.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">للوصول إلى سجل الرموز التعبيرية الخاص بك، يرجى أولاً إلغاء قُفْل جهازك.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">نصيحة للمحترفين: الضغط لفترة طويلة على الرموز التعبيرية المستخدمة مؤخرًا لإزالتها من هذا العرض مرة أخرى!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">تمت إزالة {emoji} من الرموز التعبيرية المستخدمة مؤخرًا</string>
|
||||
<string name="emoji__history__empty_message" comment="Message if the emoji history is empty">لم يتم العثور على رموز تعبيرية مستخدمة مؤخرًا. بمجرد بَدْء كتابة الرموز التعبيرية، ستظهر تلقائيًا هنا.</string>
|
||||
<string name="emoji__history__phone_locked_message" comment="Message to show if phone is locked">للوصول إلى سجل الرموز التعبيرية الخاص بك، يرجى أولاً إلغاء قُفْل جهازك.</string>
|
||||
<string name="emoji__history__usage_tip" comment="Feature discoverability for actions of emoji history">نصيحة احترافية: اضغط لفترة طويلة على الرموز التعبيرية في سجل الرموز التعبيرية لتثبيتها أو إزالتها!</string>
|
||||
<string name="emoji__history__removal_success_message" comment="Toast message if user has used the delete action on an emoji in the emoji history">تمت إزالة {emoji} من سجل الرموز التعبيرية</string>
|
||||
<string name="emoji__history__pinned">مثبّت</string>
|
||||
<string name="emoji__history__recent">الحديثة</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">سهم للأعلى</string>
|
||||
<string name="quick_action__arrow_up__tooltip">تنفيذ السهم للأعلى</string>
|
||||
@@ -83,7 +100,7 @@
|
||||
<string name="incognito_mode__toast_after_disabled">الوضع الخاص هو الان معطل افتراضيا</string>
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">الإعدادات</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">قم بتجربة اعداداتك</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">قم بتجربة أعداداتك</string>
|
||||
<string name="settings__help" comment="General label for help buttons in Settings">مساعدة</string>
|
||||
<string name="settings__default" comment="General string which is used when a preference has the default value set">الإفتراضي</string>
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">الإعداد الافتراضي</string>
|
||||
@@ -124,6 +141,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">حقل واحد على الأقل ليس له قيمة محددة. الرجاء اختيار قيمة للحقل (الحقول).</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (غير مثبت)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">التخطيطات</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">تأكيد الحذف</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">هل أنت متيقِّن أنك تريد حذف النوع الفرعي؟</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">المظهر</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">وضع الثيم</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">وقت الشروق</string>
|
||||
@@ -561,6 +580,8 @@
|
||||
<string name="devtools__show_input_state_overlay__summary" comment="Summary of Show input cache overlay in Devtools">إظهار حالة تراكب الإدخال لأغراض التطوير</string>
|
||||
<string name="devtools__show_spelling_overlay__label" comment="Label of Show spelling overlay in Devtools">أظهر طبقات التهجئة</string>
|
||||
<string name="devtools__show_spelling_overlay__summary" comment="Summary of Show spelling overlay in Devtools">إظهار نتائج تراكب التهجئة لأغراض التطوير</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__label">عرض تراكب الملء التلقائي المضمن</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__summary">تراكب مع نتائج الملء التلقائي المضمنة الحالية للتصحيح</string>
|
||||
<string name="devtools__show_key_touch_boundaries__label" comment="Label of Show key touch boundaries in Devtools">عرض حدود لمس الازرار</string>
|
||||
<string name="devtools__show_key_touch_boundaries__summary" comment="Summary of Show key touch boundaries in Devtools">رسم حد خارجي للمس الازرار باللون الاحمر</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">إظهار مساعد السحب والإفلات</string>
|
||||
@@ -576,6 +597,11 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">إعدادات أندرويد الأمنة</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">إعدادات نظام أندرويد</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">لغات النظام</string>
|
||||
<string name="devtools__debuglog__title">سجل التصحيح</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">تم نسخ سجل التصحيح إلى الحافظة</string>
|
||||
<string name="devtools__debuglog__copy_log">نسخ السجل</string>
|
||||
<string name="devtools__debuglog__copy_for_github">نسخ السجل (تنسيق GitHub)</string>
|
||||
<string name="devtools__debuglog__loading">تحميل…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">الإضافات والملحقات</string>
|
||||
<string name="ext__list__ext_theme">ملحقات السمات</string>
|
||||
@@ -734,6 +760,14 @@
|
||||
<string name="enum__display_language_names_in__system_locale__description" comment="Enum value description">يتم عرض أسماء اللغات عبر واجهة مستخدم التطبيق ولوحة المفاتيح باللغة المحلية التي تم تعيينها للجهاز بأكمله</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">اللغة الأصلية</string>
|
||||
<string name="enum__display_language_names_in__native_locale__description" comment="Enum value description">يتم عرض أسماء اللغات عبر واجهة مستخدم التطبيق ولوحة المفاتيح باللغة المحلية المشار إليها بنفسها</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend" comment="Enum value label">الفرز التلقائي (الإعداد المسبق)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend__description" comment="Enum value description">إعادة ترتيب الرموز التعبيرية تلقائيًا عند استخدام الرموز التعبيرية. تمت إضافة رموز تعبيرية جديدة إلى البداية.</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append" comment="Enum value label">الفرز التلقائي (إلحاق)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append__description" comment="Enum value description">إعادة ترتيب الرموز التعبيرية تلقائيًا عند استخدام الرموز التعبيرية. تتم إضافة رموز تعبيرية جديدة إلى النهاية.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend" comment="Enum value label">الفرز اليدوي (التمهيدي)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend__description" comment="Enum value description">لا تقم بإعادة جلب الرموز التعبيرية تلقائيًا عند استخدام الرموز التعبيرية. تمت إضافة رموز تعبيرية جديدة إلى البداية.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append" comment="Enum value label">الفرز اليدوي (إلحاق)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append__description" comment="Enum value description">لا تقم بإعادة ترتيب الرموز التعبيرية تلقائيًا عند استخدام الرموز التعبيرية. تتم إضافة رموز تعبيرية جديدة إلى النهاية.</string>
|
||||
<string name="enum__emoji_skin_tone__default" comment="Enum value label">{emoji} اللون الافتراضي للبشرة</string>
|
||||
<string name="enum__emoji_skin_tone__light_skin_tone" comment="Enum value label">{emoji} اللون الفاتح للبشرة</string>
|
||||
<string name="enum__emoji_skin_tone__medium_light_skin_tone" comment="Enum value label">{emoji} اللون الفاتح المتوسط للبشرة</string>
|
||||
@@ -745,6 +779,10 @@
|
||||
<string name="enum__emoji_hair_style__curly_hair" comment="Enum value label">{emoji} شعر مجعد</string>
|
||||
<string name="enum__emoji_hair_style__white_hair" comment="Enum value label">{emoji} شعر ابيض</string>
|
||||
<string name="enum__emoji_hair_style__bald" comment="Enum value label">{emoji} اصلع</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon">فاصلة متقدمة</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon__description" comment="Keep the :emoji_name while translating, this is a syntax guide">اقترح الرموز التعبيرية باستخدام بناء جملة:emoji_name</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text">نص المعلومات المضمنة</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text__description">اقترح الرموز التعبيرية ببساطة عن طريق كتابة اسم الرموز التعبيرية ككلمة</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates" comment="Enum value label">تجاهل المرشح</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates__description" comment="Enum value description">يضع صف الإجراءات الموسعة بين واجهة مستخدم التطبيق والصف المرشح</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates" comment="Enum value label">تحت المرشحون</string>
|
||||
@@ -876,4 +914,20 @@
|
||||
<item quantity="many">{v} عناصر</item>
|
||||
<item quantity="other">{v} عناصر</item>
|
||||
</plurals>
|
||||
<plurals name="unit__characters__written">
|
||||
<item quantity="zero">{v} حرف</item>
|
||||
<item quantity="one">{v} حرف</item>
|
||||
<item quantity="two">{v} حرفان</item>
|
||||
<item quantity="few">{v} أحرف</item>
|
||||
<item quantity="many">{v} احرف</item>
|
||||
<item quantity="other">{v} احرف</item>
|
||||
</plurals>
|
||||
<plurals name="unit__candidates__written">
|
||||
<item quantity="zero">{v} مرشح</item>
|
||||
<item quantity="one">{v} مرشح</item>
|
||||
<item quantity="two">{v} مرشحان</item>
|
||||
<item quantity="few">{v} مرشحات</item>
|
||||
<item quantity="many">{v} مرشحات</item>
|
||||
<item quantity="other">{v} مرشحون</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Fustaxes</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Fustaxes ASCII</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">الحد الأقصى لحجم سجل الرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">لون البشرة المفضل للرموز التعبيرية</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">تصفيفة الشعر الرموز التعبيرية المفضلة</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">Activar l\'historial de fustaxes</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Sorrises y fustaxes</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Persones y cuerpu</string>
|
||||
@@ -26,10 +26,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Oxetos</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Símbolos</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Banderes</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Nun s\'atopó nengún fustaxe que s\'usare apocayá. Namás que comiences a usalos, apaecen equí.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">P\'acceder al historial de fustaxes, desbloquia\'l preséu primero.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Conseyu: ¡ten primíos los fustaxes usaos apocayá pa volver quitalos d\'esta seición!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Quitóse «{emoji}» de los fustaxes usaos apocayá</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">سهم لأعلى</string>
|
||||
<string name="quick_action__arrow_up__tooltip">أداء السهم لأعلى</string>
|
||||
@@ -43,7 +39,7 @@
|
||||
<string name="quick_action__ime_ui_mode_clipboard" maxLength="12">Cartafueyu</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard__tooltip">Abrir l\'historial de fustaxes</string>
|
||||
<string name="quick_action__ime_ui_mode_media__tooltip">Abrir el panel de fustaxes</string>
|
||||
<string name="quick_action__settings" maxLength="12">Axustes</string>
|
||||
<string name="quick_action__settings" maxLength="12">Opciones</string>
|
||||
<string name="quick_action__settings__tooltip">Abrir la configuración</string>
|
||||
<string name="quick_action__undo" maxLength="12">Desfacer</string>
|
||||
<string name="quick_action__redo" maxLength="12">Refacer</string>
|
||||
@@ -54,12 +50,14 @@
|
||||
<!-- Incognito mode strings -->
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">Configuración</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">Toca equí pa probar la configuración</string>
|
||||
<string name="settings__help" comment="General label for help buttons in Settings">Ayuda</string>
|
||||
<string name="settings__default" comment="General string which is used when a preference has the default value set">Por defeutu</string>
|
||||
<string name="settings__home__title" comment="Title of the Home screen">Afáyate en {app_name}</string>
|
||||
<string name="settings__localization__title" comment="Title of languages and Layout screen">Llingües y distribuciones</string>
|
||||
<string name="settings__localization__display_language_names_in__label" comment="Label of Display language names in preference">Amosar los nomes de les llingües na</string>
|
||||
<string name="settings__localization__group_subtypes__label" comment="Label of subtypes group">Sotipos</string>
|
||||
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">Amestar un sotipu</string>
|
||||
<string name="settings__localization__language_pack_title" comment="Title of the language pack manager screen for managing installed and custom language packs">Xestionar los paquetes de llingua instalaos</string>
|
||||
<string name="settings__localization__language_pack_summary" comment="Summary of preference item for adding a new language pack">Opción esperimental: xestiona les estensiones qu\'amiesten compatibilidá pa llingües específiques (pel momentu, entrada china basada en formes)</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Llingua primaria</string>
|
||||
@@ -74,6 +72,12 @@
|
||||
<string name="settings__localization__subtype_phone_layout" comment="Label for layout dropdown in subtype dialog">Distribución primaria del tecláu telefónicu</string>
|
||||
<string name="settings__localization__subtype_phone2_layout" comment="Label for layout dropdown in subtype dialog">Distribución secundaria del tecláu telefónicu</string>
|
||||
<string name="settings__localization__subtype_summary" comment="Subtype summary">{characters_name} / {symbols_name} / {currency_set_name}</string>
|
||||
<string name="settings__localization__suggested_subtype_presets" comment="Suggested presets title">Sotipos preconfiguraos suxeríos</string>
|
||||
<string name="settings__localization__suggested_subtype_presets_none_found" comment="Suggested presets none found">Nun hai nengún stipu suxeríu. Usa\'l botón d\'abaxo pa ver tolos sotipos preconfiguraos.</string>
|
||||
<string name="settings__localization__subtype_presets" comment="Subtype presets dialog title">Sotipos preconfiguraos</string>
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">Amosar too</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">Paez que nun configuresti nengún sotipu. ¡Va usase\'l sotipu «English/QWERTY» como alternativa!</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">¡Esti sotipu yá esiste!</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Distribuciones</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Estilu</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Mou del estilu</string>
|
||||
@@ -153,6 +157,7 @@
|
||||
<string name="pref__gestures__space_bar_title" comment="Preference group title">Xestos de la barra d\'espaciu</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Configuración avanzada</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Estilu de la configuración</string>
|
||||
<string name="pref__advanced__settings_material_you__label" comment="Label of Material You preference in Advanced">Usar «Material You»</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Llingua de la configuración</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Amosar l\'iconu l\'aplicación nel llanzador</string>
|
||||
<!-- About UI strings -->
|
||||
@@ -164,7 +169,7 @@
|
||||
<string name="about__version_copied__title" comment="Title of the toast for copying the version string">La versión copióse al cartafueyu</string>
|
||||
<string name="about__version_copied__error" comment="Title of the error toast for copying the version string">Prodúxose daqué malo: {error_message}</string>
|
||||
<string name="about__changelog__title" comment="Preference title">Rexistru de cambeos</string>
|
||||
<string name="about__changelog__summary" comment="Preference summary">Les novedaes</string>
|
||||
<string name="about__changelog__summary" comment="Preference summary">Contién les novedaes</string>
|
||||
<string name="about__repository__title" comment="Preference title">Depósitu (GitHub)</string>
|
||||
<string name="about__repository__summary" comment="Preference summary">El códigu fonte, los discutinios, los problemes y más información</string>
|
||||
<string name="about__privacy_policy__title" comment="Preference title">Política de privacidá</string>
|
||||
@@ -175,15 +180,25 @@
|
||||
<string name="about__third_party_licenses__summary" comment="Preference summary">Les llicencies de les biblioteques de terceros que s\'inclúin nesta aplicación</string>
|
||||
<!-- Setup UI strings -->
|
||||
<string name="setup__title" comment="Title of Setup">¡Afáyate!</string>
|
||||
<string name="setup__intro_message" comment="Short intro message welcoming new users">¡Gracies por usar {app_name}! Esta configuración rápida va guiate pelos pasos necesarios pa usar {app_name} nel preséu.</string>
|
||||
<string name="setup__footer__privacy_policy" comment="Privacy policy label for URL">Política de privacidá</string>
|
||||
<string name="setup__footer__repository" comment="Repository label for URL">Depósitu</string>
|
||||
<string name="setup__enable_ime__title">Activación de {app_name}</string>
|
||||
<string name="setup__enable_ime__description">Android rique que tolos teclaos personalizaos s\'activen per separtao enantes de poder usalos. Vete a la configuración de <i>Llingua y entrada</i> p\'activar «{app_name}» ellí.</string>
|
||||
<string name="setup__enable_ime__open_settings_btn">Abrir la configuración del sistema</string>
|
||||
<string name="setup__select_ime__title">Seleición de {app_name}</string>
|
||||
<string name="setup__select_ime__description">{app_name} yá ta activáu nel sistema. Pa usalu, escueyi «{app_name}» nel diálogu del selector d\'entrada.</string>
|
||||
<string name="setup__select_ime__switch_keyboard_btn">Cambiar de tecláu</string>
|
||||
<string name="setup__grant_notification_permission__title">Avisos pa informar de casques</string>
|
||||
<string name="setup__grant_notification_permission__description">A partir d\'Android 13, les aplicaciones tienen de pidir
|
||||
permisu pa unviar avisos. En FlorisBoard, esti permisu namás s\'usa p\'abrir la pantalla d\'informar casques al producise dalgún.
|
||||
Pues camudar esti permisu cuando quieras na configuración del sistema.
|
||||
</string>
|
||||
<string name="setup__grant_notification_permission__btn">Conceder el permisu</string>
|
||||
<string name="setup__finish_up__title">Fin</string>
|
||||
<string name="setup__finish_up__description_p1">{app_name} ta activáu nel sistema y yá pues personalizalu.</string>
|
||||
<string name="setup__finish_up__description_p2">Si atopes cualesquier problema, fallu, casque o namás quier facer dalguna suxerencia, revisa\'l depósitu del proyeutu na pantalla «Tocante a».</string>
|
||||
<string name="setup__finish_up__description_p2">Si atopes cualesquier problema, fallu, casque o namás quier facer dalguna suxerencia, consulta\'l depósitu del proyeutu na pantalla «Tocante a».</string>
|
||||
<string name="setup__finish_up__finish_btn">Comenzar a personalizar</string>
|
||||
<!-- Back up & Restore -->
|
||||
<string name="backup_and_restore__back_up__destination_file_sys">Sistema de ficheros llocal</string>
|
||||
<string name="backup_and_restore__back_up__destination_share_intent">Aplicación de terceros pel menú de compartición</string>
|
||||
@@ -213,7 +228,7 @@
|
||||
<string name="send_to_clipboard__type_not_supported_error">Esti elementu multimedia nun ye compatible.</string>
|
||||
<!-- Devtools strings -->
|
||||
<string name="devtools__title" comment="Title of Devtools screen. Translators: treat this string as 'Developer tools' for translation, except a similar short term is available for your language.">Ferramientes de desendolcu</string>
|
||||
<string name="devtools__enabled__summary" comment="Summary of Enable developer tools in Devtools">Ferramientes diseñaes específicamente pa depurar y iguar problemes</string>
|
||||
<string name="devtools__enabled__summary" comment="Summary of Enable developer tools in Devtools">Ferramientes diseñaes específicamente pa depurar ya iguar problemes</string>
|
||||
<string name="devtools__show_key_touch_boundaries__label" comment="Label of Show key touch boundaries in Devtools">Amosar les llendes táctiles de les tecles</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">Amosar los ayudantes de la función «drag&drop»</string>
|
||||
<string name="devtools__reset_flag_is_ime_set_up__summary" comment="Summary of Reset is IME set up flag in Devtools">Una aición de depuración pa volver amosar la pantalla de configuración</string>
|
||||
@@ -235,7 +250,7 @@
|
||||
<string name="ext__error__not_found_description">Nun se pudo atopar nenguna estensión cola ID «{id}».</string>
|
||||
<string name="ext__editor__title_create_any">Creación d\'una estensión</string>
|
||||
<string name="ext__editor__metadata__title_invalid">Los metadatos nun son válidos</string>
|
||||
<string name="ext__editor__metadata__message_invalid">Los metadatos d\'esta estensión nun son válidos. ¡Revisa l\'editor de metadatos pa consiguir más detalles!</string>
|
||||
<string name="ext__editor__metadata__message_invalid">Los metadatos d\'esta estensión nun son válidos. ¡Consulta l\'editor de metadatos pa consiguir más detalles!</string>
|
||||
<string name="ext__editor__dependencies__title">Xestionar les dependencies</string>
|
||||
<string name="ext__editor__create_component__title_theme">Creación d\'un estilu</string>
|
||||
<string name="ext__export__failure">La esportación de la estensión falló: {error_message}</string>
|
||||
@@ -246,6 +261,9 @@
|
||||
<string name="ext__validation__enter_title">Introduz un títulu</string>
|
||||
<string name="ext__validation__enter_valid_number">Introduz nun númberu válidu</string>
|
||||
<string name="ext__validation__enter_positive_number">Introduz un númberu positivu (>=0)</string>
|
||||
<string name="ext__update_box__search_for_updates">Buscar anovamientos</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Dir a «{ext_home_title}»</string>
|
||||
<string name="ext__home__visit_store">Visitar la tienda de complementos</string>
|
||||
<!-- Action strings -->
|
||||
<string name="action__add">Amestar</string>
|
||||
<string name="action__apply">Aplicar</string>
|
||||
|
||||
@@ -13,9 +13,24 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Емоции</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Емоции</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Каомоджи</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Дължина на историята на емоциите</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Предпочитан цвят на кожата за емоции</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Предпочитана прическа за емоции</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">История на емоциите</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">Включване на историята на емоциите</string>
|
||||
<string name="prefs__media__emoji_history_enabled__summary" comment="Preference summary">Запазване на използваните емоции за по-бърз достъп</string>
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">Стратегия за обновяване (закачени)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">Стратегия за обновяване (последни)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">Максимален брой елементи</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Предложения за емоции</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Включване на предложенията за емоции</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Показва предложения за емоции докато въвеждате</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Вид на задействането</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Обновяване на историята на емоциите</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Приемане на предложената емиция я добавя в историята на емоции</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Показване на името на емоцията</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Предложенията за емоции включват и името</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Минимална дължина на заявка</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Максимален брой кандидати</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Усмивки и емоции</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Хора и тяло</string>
|
||||
@@ -26,10 +41,12 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Предмети</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Символи</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Знамена</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Скоро не сте ползвали еможи. Като започнете да използвате ще се показват тук.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">За достъп до последно използваните емоции отключете устройството.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Подсказка: За да премахнете емоциите от този списък задръжте върху него!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Премахнато е {emoji} от последно използваните</string>
|
||||
<string name="emoji__history__empty_message" comment="Message if the emoji history is empty">Скоро не сте използвали емоции. Започнете да използвате и ще бъдат показани тук.</string>
|
||||
<string name="emoji__history__phone_locked_message" comment="Message to show if phone is locked">За достъп до последно използваните емоции отключете устройството.</string>
|
||||
<string name="emoji__history__usage_tip" comment="Feature discoverability for actions of emoji history">Подсказка: Задръжте върху емоция в историята, за да я закачите или премахнате!</string>
|
||||
<string name="emoji__history__removal_success_message" comment="Toast message if user has used the delete action on an emoji in the emoji history">Емоцията {emoji} е премахната от историята</string>
|
||||
<string name="emoji__history__pinned">Закачени</string>
|
||||
<string name="emoji__history__recent">Последни</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Нагоре</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Извършва стрелка нагоре</string>
|
||||
@@ -89,13 +106,13 @@
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">По подразбиране от системата</string>
|
||||
<string name="settings__home__title" comment="Title of the Home screen">Добре дошли във {app_name}</string>
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">Клавиатурата FlorisBoard не е активна в системата и не е достъпна като метод за въвеждане. Докоснете тук, за да промените.</string>
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">Клавиатурата FlorisBoard не е избрана като подразбиран метод за въвеждане. Докоснете тук, за да направите промяна.</string>
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">Клавиатурата FlorisBoard не е избрана като подразбиран метод за въвеждане. Докоснете, за да направите промяната.</string>
|
||||
<string name="settings__localization__title" comment="Title of languages and Layout screen">Езици и подредби</string>
|
||||
<string name="settings__localization__display_language_names_in__label" comment="Label of Display language names in preference">Изписване на езиците на</string>
|
||||
<string name="settings__localization__group_subtypes__label" comment="Label of subtypes group">Подредби</string>
|
||||
<string name="settings__localization__subtype_add_title" comment="Title of subtype dialog when adding a new subtype">Добавяне на подредба</string>
|
||||
<string name="settings__localization__language_pack_title" comment="Title of the language pack manager screen for managing installed and custom language packs">Управление на инсталираните езикови пакети</string>
|
||||
<string name="settings__localization__language_pack_summary" comment="Summary of preference item for adding a new language pack">Ексоериментално: управление на добавки за поддръжка на ооределени езици (въвеждане чрез фигури на китайски език)</string>
|
||||
<string name="settings__localization__language_pack_summary" comment="Summary of preference item for adding a new language pack">Експериментално: управление на добавки за поддръжка на определени езици (въвеждане чрез фигури на китайски език)</string>
|
||||
<string name="settings__localization__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">Променяне на подредба</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Основен език</string>
|
||||
<string name="settings__localization__subtype_popup_mapping" comment="Label for popup mapping dropdown in subtype screen">Подсказки</string>
|
||||
@@ -124,6 +141,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Има поле е без стойност. Изберете стойност за всички полета.</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (не е инсталирано)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Подредби</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Потвърждение при премахване</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">Желаете ли да премахнете този подвид?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Тема</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Режим на тема</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Време на изгрев</string>
|
||||
@@ -513,7 +532,7 @@
|
||||
<string name="clipboard__locked__message">За достъп до междинната памет отключете устройството.</string>
|
||||
<string name="clipboard__group_pinned">Закачени</string>
|
||||
<string name="clipboard__group_recent">Последни</string>
|
||||
<string name="clipboard__group_other">Друго</string>
|
||||
<string name="clipboard__group_other">Други</string>
|
||||
<string name="clipboard__item_description_email">Електронна поща</string>
|
||||
<string name="clipboard__item_description_url">Адрес</string>
|
||||
<string name="clipboard__item_description_phone">Телефон</string>
|
||||
@@ -540,7 +559,7 @@
|
||||
<string name="pref__clipboard__enable_clipboard_history__summary">Запазване на копираното за по-бърз достъп до него</string>
|
||||
<string name="pref__clipboard__clean_up_old__label">Премахване на стари елементи</string>
|
||||
<string name="pref__clipboard__clean_up_after__label">Премахване на старите елементи след</string>
|
||||
<string name="pref__clipboard__limit_history_size__label">Ограничаване на броя</string>
|
||||
<string name="pref__clipboard__limit_history_size__label">Ограничаване на броя елементи</string>
|
||||
<string name="pref__clipboard__max_history_size__label">Максимален брой елементи</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__label">Изчистване на текущата межд. памет влияе на историята</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__summary">Изчистване на текущото съдържание на междинната памет изчиства и последния елемент от историята</string>
|
||||
@@ -560,6 +579,8 @@
|
||||
<string name="devtools__show_input_state_overlay__summary" comment="Summary of Show input cache overlay in Devtools">Слой със състоянието на полето за въвеждане, за отстраняване на дефекти</string>
|
||||
<string name="devtools__show_spelling_overlay__label" comment="Label of Show spelling overlay in Devtools">Слой за проверка на правописа</string>
|
||||
<string name="devtools__show_spelling_overlay__summary" comment="Summary of Show spelling overlay in Devtools">Слой със съдържанието от проверката на правопис, за отстраняване на дефекти</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__label">Автоматично попълване в слой</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__summary">Слой с резултатите от автоматичното попълване, за отстраняване на дефекти</string>
|
||||
<string name="devtools__show_key_touch_boundaries__label" comment="Label of Show key touch boundaries in Devtools">Видим контур на клавишите</string>
|
||||
<string name="devtools__show_key_touch_boundaries__summary" comment="Summary of Show key touch boundaries in Devtools">Оцветяване на контура на клавишите в червено</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">Манипулатори за влачене и пускане</string>
|
||||
@@ -575,6 +596,11 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Настройки на сигурността на Android</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Системни настройки на Android</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Езици на системата</string>
|
||||
<string name="devtools__debuglog__title">Дневник за отстраняване на дефекти</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">Съдържанието на дневника е копирано</string>
|
||||
<string name="devtools__debuglog__copy_log">Копиране</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Копиране (форматирано за Гитхъб)</string>
|
||||
<string name="devtools__debuglog__loading">Зареждане…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Добавки и разширения</string>
|
||||
<string name="ext__list__ext_theme">Добавки за теми</string>
|
||||
@@ -657,8 +683,8 @@
|
||||
<string name="ext__validation__enter_number_between_0_100">Въведете положително число между 0 и 100</string>
|
||||
<string name="ext__validation__hint_value_above_50_percent">Стойности над 50% ще бъдат приравнени на 50%, така че намалете стойността</string>
|
||||
<string name="ext__update_box__internet_permission_hint">Понеже приложението няма достъп до интернет, проверката за обновяване на инсталираните разширения се извършва ръчно.</string>
|
||||
<string name="ext__update_box__search_for_updates">Проверка за обновявания</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">Управлявани {extensions}</string>
|
||||
<string name="ext__update_box__search_for_updates">Проверка за обновяване</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">Управление на {extensions}</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">Всички дейности, свързани с внасяне, изнасяне, създаване, промяна и премахване на разширения могат да бъдат извършване през Управление на разширения.</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Към {ext_home_title}</string>
|
||||
<string name="ext__home__info">Можете да изтегляте и инсталирате разширения от магазина за добавки на FlorisBoard или да внесете файл на разширение, който сте изтеглили от интернет.</string>
|
||||
@@ -672,7 +698,7 @@
|
||||
<string name="action__back_up">Резервно копие</string>
|
||||
<string name="action__cancel">Отказ</string>
|
||||
<string name="action__create">Създаване</string>
|
||||
<string name="action__default">По подразбиране</string>
|
||||
<string name="action__default">Стандартни</string>
|
||||
<string name="action__delete">Премахване</string>
|
||||
<string name="action__delete_confirm_title">Потвърждаване на изтриване</string>
|
||||
<string name="action__delete_confirm_message">Наистина ли искате да изтриете „{name}“? Това действие веднъж изпълнено не може да бъде отменено.</string>
|
||||
@@ -733,6 +759,14 @@
|
||||
<string name="enum__display_language_names_in__system_locale__description" comment="Enum value description">Имената на езиците в приложението и клавиатурата са на подразбирания за устройствто език</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">Присъщия за езика</string>
|
||||
<string name="enum__display_language_names_in__native_locale__description" comment="Enum value description">Имената на езиците в приложението и клавиатурата са на присъщия за езика</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend" comment="Enum value label">Автом. сортиране (добавяне отпред)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend__description" comment="Enum value description">Автоматично сортиране при използване на емоция. Новите емоции биват добавени в началото.</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append" comment="Enum value label">Автом. сортиране (добавяне отзад)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append__description" comment="Enum value description">Автоматично сортиране при използване на емоция. Новите емоции биват добавени в края.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend" comment="Enum value label">Ръчно сортиране (добавяне отпред)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend__description" comment="Enum value description">Без автоматично сортиране при използване на емоция. Новите емоции биват добавени в началото.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append" comment="Enum value label">Ръчно сортиране (добавяне отзад)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append__description" comment="Enum value description">Без автоматично сортиране при използване на емоция. Новите емоции биват добавени в края.</string>
|
||||
<string name="enum__emoji_skin_tone__default" comment="Enum value label">{emoji} Подразбиран цвят на кожата</string>
|
||||
<string name="enum__emoji_skin_tone__light_skin_tone" comment="Enum value label">{emoji} Светъл цвят на кожа</string>
|
||||
<string name="enum__emoji_skin_tone__medium_light_skin_tone" comment="Enum value label">{emoji} Средно светъл цвят на кожата</string>
|
||||
@@ -744,6 +778,10 @@
|
||||
<string name="enum__emoji_hair_style__curly_hair" comment="Enum value label">{emoji} Къдрава коса</string>
|
||||
<string name="enum__emoji_hair_style__white_hair" comment="Enum value label">{emoji} Бял цвят на косата</string>
|
||||
<string name="enum__emoji_hair_style__bald" comment="Enum value label">{emoji} Без коса</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon">Водещо двоеточие</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon__description" comment="Keep the :emoji_name while translating, this is a syntax guide">Предлагане на емоции чрез синтаксиса :име_на_емоция</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text">Обикновен текст</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text__description">Предлагане на емоции чрез въвеждане на името на емоцията като дума</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates" comment="Enum value label">Над кандидатите</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates__description" comment="Enum value description">Добавя се реда с допълнителни действия между приложението и реда с кандидати</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates" comment="Enum value label">Под кандидатите</string>
|
||||
@@ -859,4 +897,12 @@
|
||||
<item quantity="one">{v} елемент</item>
|
||||
<item quantity="other">{v} елемента</item>
|
||||
</plurals>
|
||||
<plurals name="unit__characters__written">
|
||||
<item quantity="one">{v} знак</item>
|
||||
<item quantity="other">{v} знака</item>
|
||||
</plurals>
|
||||
<plurals name="unit__candidates__written">
|
||||
<item quantity="one">{v} кандидат</item>
|
||||
<item quantity="other">{v} кандидата</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojis</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticones</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Mida màxima de l\'historial d\'emojis</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">To de pell preferit dels emojis</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Pentinat preferit dels emojis</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,9 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objectes</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Símbols</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Banderes</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">No s\'han trobat emojis recents. En començar a escriure emojis, apareixeran automàticament aquí.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Consell: Manteniu premut els emojis recents per a suprimir-los d\'aquesta llista!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">S\'ha suprimit {emoji} dels emojis recents</string>
|
||||
<!-- Quick action strings -->
|
||||
<!-- Incognito mode strings -->
|
||||
<!-- Settings UI strings -->
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">خەندەکان</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">هێمای دەربڕینی هەستەکان</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">کامۆجی</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">ڕێژەی پیشاندانی خەندە لە مێژووی خەندەکان</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">ڕەنگی بنەڕەتی خەندەکان</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">ڕەنگی بنەڕەتی قژی خەندەکان</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,9 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">ئامانجەکان</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">هێماکان</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">ئاڵاکان</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">هیچ ئیمۆجیەک بەکارنەهاتووە، هەرکاتێ ئیمۆجیەکانت بەکارهێنا بەشێوەیەکی خۆکاری لێرەدا دەردەکەون.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">زانیاری: بۆ سڕینەوەی ئیمۆجیەکان لەم بەشەدا کەمێک دەستی لەسەر ڕابگرە.</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">ئیمۆجی {emoji} لابرا لەلیستی دوایین بەکارهاتووەکان</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">چونە سەرەوە</string>
|
||||
<string name="quick_action__arrow_up__tooltip">چوونە سەرەتای دێڕ</string>
|
||||
|
||||
@@ -13,9 +13,24 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emotikony</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emotikony</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Maximální velikost historie emotikonů</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Preferovaná barva pokožky emotikonů</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Preferovaný styl vlasů emotikonů</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">Historie emotikonů</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">Zapnout historii emotikonů</string>
|
||||
<string name="prefs__media__emoji_history_enabled__summary" comment="Preference summary">Uchovávat nedávno použité emotikony pro rychlý přístup</string>
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">Strategie aktualizace (připnuté)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">Strategie aktualizace (nedávné)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">Maximální počet položek k uchování</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Návrhy emotikonů</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Povolit návrhy emotikonů</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Poskytovat návrhy emotikonů, zatímco píšete</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Typ spouštěče</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Aktualizovat historii emotikonů</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Přijetí navržených emotikonů je přidá do historie emotikonů</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Zobrazit název emotikonu</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Návrhy emotikonů zobrazují název vedle emotikonu</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Minimální délka textu</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Maximální počet kandidátů</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smajlíky a emotikony</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Lidé a tělo</string>
|
||||
@@ -26,10 +41,12 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Předměty</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symboly</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Vlajky</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Nenalezeny žádné nedávno použité emotikony. Jakmile je začnete psát, objeví se automaticky zde.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Pro přístup k historii smajlíků nejprve prosím odemkněte své zařízení.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Tip: Stiskněte a držte prst na naposledy použitých emotikonech pro jejich odebrání z daného seznamu!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Emotikon {emoji} bylo odebráno z nedávno použitých</string>
|
||||
<string name="emoji__history__empty_message" comment="Message if the emoji history is empty">Nenalezeny žádné nedávno použité emotikony. Jakmile je začnete psát, objeví se automaticky zde.</string>
|
||||
<string name="emoji__history__phone_locked_message" comment="Message to show if phone is locked">Pro přístup k historii emotikonů nejprve prosím odemkněte své zařízení.</string>
|
||||
<string name="emoji__history__usage_tip" comment="Feature discoverability for actions of emoji history">Tip: dlouze stiskněte emotikony v historii emotikonů pro jejich připnutí nebo odstranění!</string>
|
||||
<string name="emoji__history__removal_success_message" comment="Toast message if user has used the delete action on an emoji in the emoji history">Emotikon {emoji} odstraněn z historie</string>
|
||||
<string name="emoji__history__pinned">Připnuté</string>
|
||||
<string name="emoji__history__recent">Nedávné</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Šipka nahoru</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Vykonat šipku nahoru</string>
|
||||
@@ -124,6 +141,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Minimálně jedno pole nemá vybranou hodnotu. Vyberte ji prosím.</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (nenainstalováno)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Rozložení</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Potvrzení odstranění</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">Opravdu chcete odstranit tento podtyp?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Motiv</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Režim motivu</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Čas východu slunce</string>
|
||||
@@ -563,6 +582,8 @@
|
||||
<string name="devtools__show_input_state_overlay__summary" comment="Summary of Show input cache overlay in Devtools">Zobrazí aktuální stav vstupu pro ladění</string>
|
||||
<string name="devtools__show_spelling_overlay__label" comment="Label of Show spelling overlay in Devtools">Zobrazit překrytí s pravopisem</string>
|
||||
<string name="devtools__show_spelling_overlay__summary" comment="Summary of Show spelling overlay in Devtools">Zobrazí aktuální výsledky pravopisu pro ladění</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__label">Zobrazit překrytí automatického vyplňování na řádku</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__summary">Zobrazí aktuální výsledky automatického vyplňování na řádku pro ladění</string>
|
||||
<string name="devtools__show_key_touch_boundaries__label" comment="Label of Show key touch boundaries in Devtools">Zobrazit hranice dotyku kláves</string>
|
||||
<string name="devtools__show_key_touch_boundaries__summary" comment="Summary of Show key touch boundaries in Devtools">Zobrazit červené ohraničení hranic dotyku kláves</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">Zobrazit pomocníky drag&drop</string>
|
||||
@@ -578,6 +599,11 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Bezpečná nastavení Androidu</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Systémová nastavení Androidu</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Systémové jazyky</string>
|
||||
<string name="devtools__debuglog__title">Protokol ladění</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">Protokol ladění zkopírován do schránky</string>
|
||||
<string name="devtools__debuglog__copy_log">Kopírovat protokol</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Kopírovat protokol (formátování GitHub)</string>
|
||||
<string name="devtools__debuglog__loading">Načítání…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Doplňky a rozšíření</string>
|
||||
<string name="ext__list__ext_theme">Rozšíření témat</string>
|
||||
@@ -663,7 +689,7 @@
|
||||
<string name="ext__update_box__search_for_updates">Vyhledat aktualizace</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">Správa {extensions}</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">Všechny úlohy spojené s importováním, exportováním, vytvářením, přizpůsobováním a odstraňováním rozšíření mohou být prováděny skrze centralizovaného správce doplňků.</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Přejít {ext_home_title}</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Přejít na {ext_home_title}</string>
|
||||
<string name="ext__home__info">Rozšíření můžete stahovat a instalovat z Obchodu s doplňky FlorisBoard nebo importovat jakýkoli soubor rozšíření, který jste si stáhli z internetu.</string>
|
||||
<string name="ext__home__visit_store">Navštívit Obchod s doplňky</string>
|
||||
<string name="ext__home__manage_extensions">Správa nainstalovaných doplňků</string>
|
||||
@@ -736,6 +762,14 @@
|
||||
<string name="enum__display_language_names_in__system_locale__description" comment="Enum value description">Názvy jazyků napříč aplikací a rozhraním klávesnice jsou zobrazeny v jazyce, který je nastaven pro celé zařízení</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">Nativní jazyk</string>
|
||||
<string name="enum__display_language_names_in__native_locale__description" comment="Enum value description">Názvy jazyků napříč aplikací a rozhraním klávesnice jsou zobrazeny ve svém vlastním jazyce</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend" comment="Enum value label">Automatické řazení (na začátku)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend__description" comment="Enum value description">Automaticky seřazovat emotikony podle jejich používání. Nové emotikony budou přidávány na začátek.</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append" comment="Enum value label">Automatické řazení (na konci)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append__description" comment="Enum value description">Automaticky seřazovat emotikony podle jejich používání. Nové emotikony budou přidávány na konec.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend" comment="Enum value label">Ruční řazení (na začátku)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend__description" comment="Enum value description">Neseřazovat automaticky emotikony podle jejich používání. Nové emotikony budou přidávány na začátek.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append" comment="Enum value label">Ruční řazení (na konci)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append__description" comment="Enum value description">Neseřazovat automaticky emotikony podle jejich používání. Nové emotikony budou přidávány na konec.</string>
|
||||
<string name="enum__emoji_skin_tone__default" comment="Enum value label">{emoji} Výchozí barva pleti</string>
|
||||
<string name="enum__emoji_skin_tone__light_skin_tone" comment="Enum value label">{emoji} Světlá barva pleti</string>
|
||||
<string name="enum__emoji_skin_tone__medium_light_skin_tone" comment="Enum value label">{emoji} Středně světlá barva pleti</string>
|
||||
@@ -747,9 +781,13 @@
|
||||
<string name="enum__emoji_hair_style__curly_hair" comment="Enum value label">{emoji} Kurdnaté vlasy</string>
|
||||
<string name="enum__emoji_hair_style__white_hair" comment="Enum value label">{emoji} Bílé vlasy</string>
|
||||
<string name="enum__emoji_hair_style__bald" comment="Enum value label">{emoji} Pleš</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon">Počáteční dvojtečka</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon__description" comment="Keep the :emoji_name while translating, this is a syntax guide">Navrhovat emotikony pomocí syntaxe :emoji_name</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text">Text v řádku</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text__description">Navrhovat emotikony jednoduše zadáním názvu emotikonu jako slova</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates" comment="Enum value label">Nad navrženými slovy</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates__description" comment="Enum value description">Umístí řádek rozšířených akcí mezi UI aplikace a řádek navrhnutých slov</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates" comment="Enum value label">Pod navrhnutými slovy</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates" comment="Enum value label">Pod navrženými slovy</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates__description" comment="Enum value description">Umístí řádek rozšířených akcí mezi řádek s navrhnutými slovy a textovou klávesnici</string>
|
||||
<string name="enum__extended_actions_placement__overlay_app_ui" comment="Enum value label">Překrýt rozhraní aplikace</string>
|
||||
<string name="enum__extended_actions_placement__overlay_app_ui__description" comment="Enum value description">Umístí řádek rozšířených akcí jako překrytí nad UI aplikace, bez ovlivnění výšky rozhraní klávesnice. Vezměte prosím na vědomí, že toto umístění může způsobit částečné překreslení vstupního pole aplikace</string>
|
||||
@@ -870,4 +908,16 @@
|
||||
<item quantity="many">{v} položek</item>
|
||||
<item quantity="other">{v} položek</item>
|
||||
</plurals>
|
||||
<plurals name="unit__characters__written">
|
||||
<item quantity="one">{v} znak</item>
|
||||
<item quantity="few">{v} znaky</item>
|
||||
<item quantity="many">{v} znaků</item>
|
||||
<item quantity="other">{v} znaků</item>
|
||||
</plurals>
|
||||
<plurals name="unit__candidates__written">
|
||||
<item quantity="one">{v} návrh</item>
|
||||
<item quantity="few">{v} návrhy</item>
|
||||
<item quantity="many">{v} návrhů</item>
|
||||
<item quantity="other">{v} návrhů</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojis</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Humørikoner</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Tekst-emoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Maks. størrelse på emoji-historik</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Foretrukken emoji-hudfarve</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Foretrukken emoji-frisure</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,10 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objekter</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symboler</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Flag</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Ingen nyligt brugte emojis fundet. Når du begynder at skrive emojis, vil de automatisk blive vist her.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">For at få adgang til din emoji-historik skal du først låse din enhed op.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro tip: Tryk længe på nyligt brugte emojis for at fjerne dem fra denne visning igen!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Fjernet {emoji} fra nyligt brugte emojis</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Pil op</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Udfør pil op</string>
|
||||
@@ -52,10 +47,13 @@
|
||||
<string name="quick_action__toggle_incognito_mode__tooltip">Slå inkognito-tilstand til/fra</string>
|
||||
<string name="quick_action__voice_input" maxLength="12">Stemmeinput</string>
|
||||
<string name="quick_action__voice_input__tooltip" comment="IME stands for Input Method Editor and is indirectly equivalent to 'keyboard'.">Åbn stemmeinput-udbyder</string>
|
||||
<string name="quick_action__one_handed_mode__tooltip">Skift enhåndstilstand</string>
|
||||
<string name="quick_action__drag_marker__tooltip" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Nuværende træk-markør position</string>
|
||||
<string name="quick_action__noop" maxLength="12" comment="Noop=no operation; this action is only used as a placeholder in the actions editor drag and drop screen">Ingen</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">Indstillinger</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">Prøv din opsætning</string>
|
||||
<string name="settings__help" comment="General label for help buttons in Settings">Hjælp</string>
|
||||
<string name="settings__default" comment="General string which is used when a preference has the default value set">Standard</string>
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">Systemstandard</string>
|
||||
@@ -69,11 +67,14 @@
|
||||
<string name="settings__localization__language_pack_title" comment="Title of the language pack manager screen for managing installed and custom language packs">Administrér installerede sprogpakker</string>
|
||||
<string name="settings__localization__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">Ændre undertastatur</string>
|
||||
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">Primært sprog</string>
|
||||
<string name="settings__localization__subtype_suggestion_provider" comment="Label for suggestion provider dropdown in subtype dialog">Inkognito-tilstand er nu aktiveret. Vil ikke lærer ord fra dine input mens denne tilstand er aktiv</string>
|
||||
<string name="settings__localization__subtype_select_locale" comment="Subtype select language title">Vælg sprog</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">Det ser ud til, at der ikke er konfigureret nogle undertastaturer. I dette tilfælde faldes der tilbage på Engelsk/QWERTY!</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Dette undertastatur findes allerede!</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (ikke installeret)</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Tema</string>
|
||||
<string name="settings__theme_editor__rule_selectors"></string>
|
||||
<string name="snygg__rule_element__keyboard">Tastatur vindue</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Aktivér lydfeedback</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">Vibrationsvarighed</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">Vibrationsstyrke</string>
|
||||
|
||||
@@ -13,9 +13,24 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojis</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticons</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Maximale Größe des Emoji-Verlaufs</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Bevorzugte Emoji-Hautfarbe</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Bevorzugte Emoji-Haarfarbe</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">Emoji-Historie</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">Aktiviere Emoji-Historie</string>
|
||||
<string name="prefs__media__emoji_history_enabled__summary" comment="Preference summary">Behalte kürzlich genutzte Emojis für einen schnellen Zugriff</string>
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">Update Strategie (gepinnt)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">Update Strategie (kürzlich)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">Maximale zu behaltende Emojis</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Emoji Vorschläge</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Aktiviere Emoji Vorschläge</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Erhalte Emoji Vorschläge während des Tippens</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Auslösetyp</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Update Emoji-Historie</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Angenommene vorgeschlagene Emojis werden zur Emoji-Historie hinzugefügt</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Zeige Emoji Name</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Emoji Vorschläge zeigen den Namen neben dem Emoji</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Minimale Suchbegriff-Länge</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Maximale Anzahl von Vorschlägen</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smileys & Emotionen</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Personen & Körper</string>
|
||||
@@ -26,10 +41,12 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objekte</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symbole</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Flaggen</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Keine kürzlich verwendeten Emojis gefunden. Sobald Sie Emojis verwendet haben erscheinen diese hier.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Um auf deinen Emoji-verlauf zuzugreifen, entsperre zuerst dein Gerät.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro Tipp: Halten Sie kürzlich verwendete Emojis gedrückt, um diese wieder aus dieser Ansicht zu entfernen!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji} wurde aus \"kürzlich verwendeten Emojis\" entfernt</string>
|
||||
<string name="emoji__history__empty_message" comment="Message if the emoji history is empty">Keine kürzlich benutzen Emojis gefunden. Sobald Emojis benutzt werden, erscheinen diese hier.</string>
|
||||
<string name="emoji__history__phone_locked_message" comment="Message to show if phone is locked">Um auf deinen Emoji-Historie zuzugreifen, entsperre das Gerät.</string>
|
||||
<string name="emoji__history__usage_tip" comment="Feature discoverability for actions of emoji history">Tipp: Tippe lange auf Emojis in der Historie um sie anzupinnen oder zu entfernen!</string>
|
||||
<string name="emoji__history__removal_success_message" comment="Toast message if user has used the delete action on an emoji in the emoji history">{emoji} aus Historie gelöscht</string>
|
||||
<string name="emoji__history__pinned">Angepinnt</string>
|
||||
<string name="emoji__history__recent">Kürzlich</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Pfeil hoch</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Pfeil nach oben ausführen</string>
|
||||
@@ -124,6 +141,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">In mindestens einem Feld ist kein Wert ausgewählt. Bitte wähle einen Wert für das Feld / die Felder.</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (nicht installiert)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Layouts</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Löschen bestätigen</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">Bist du sicher, dass du diesen Untertyp löschen willst?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Design</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Design-Modus</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Sonnenuntergangszeit</string>
|
||||
@@ -160,7 +179,7 @@
|
||||
<string name="settings__theme_editor__code_recording_help_text">Um den Code einer Taste zu ermitteln, verwenden Sie die Schaltfläche neben dem Code-Eingabefeld. Sobald sie aktiviert ist, zeichnet sie den nächsten Tastendruck auf und fügt den Code in das Eingabefeld ein.</string>
|
||||
<string name="settings__theme_editor__code_recording_started">Key code aufnahme gestartet</string>
|
||||
<string name="settings__theme_editor__code_recording_stopped">Key code aufnahme beendet</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} muss die standard Tastatur-App sein, um eine Taste aufzunehmen</string>
|
||||
<string name="settings__theme_editor__code_recording_requires_default_ime_floris">{app_name} muss die Standard-Tastatur-App sein, um eine Taste aufzunehmen</string>
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Aufnahme läuft …</string>
|
||||
<string name="settings__theme_editor__add_property">Eigenschaft hinzufügen</string>
|
||||
<string name="settings__theme_editor__edit_property">Eigenschaft bearbeiten</string>
|
||||
@@ -378,7 +397,7 @@
|
||||
<string name="settings__udm__dialog__shortcut_label" comment="Label for the shortcut in the user dictionary add/edit dialog">Abkürzung (optional)</string>
|
||||
<string name="settings__udm__dialog__shortcut_error_invalid" comment="Error label for the shortcut in the user dictionary add/edit dialog">Bitte einen Shortcut eingeben, der zu {regex} passt</string>
|
||||
<string name="settings__udm__dialog__locale_label" comment="Label for the language code in the user dictionary add/edit dialog">Sprachcode (optional)</string>
|
||||
<string name="settings__udm__dialog__locale_error_invalid" comment="Error label for the language code in the user dictionary add/edit dialog">Dieses Sprachcode entspicht nicht denn enstpächende Syntax. Der Code muss entsprechend von Land (wie en), Land und Region (wie en_US) oder Land, Region und Script (wie en_US-script).</string>
|
||||
<string name="settings__udm__dialog__locale_error_invalid" comment="Error label for the language code in the user dictionary add/edit dialog">Dieser Sprachcode entspricht nicht der Syntax. Der Code muss entweder ein Land (wie en), Land und Region (wie en_US) oder Land, Region und Script (wie en_US-script) sein.</string>
|
||||
<string name="settings__gestures__title" comment="Title of Gestures screen">Gesten & Glide Typing</string>
|
||||
<string name="pref__glide__title" comment="Preference group title">Glide Typing</string>
|
||||
<string name="pref__glide__enabled__label" comment="Preference title">Glide Typing aktivieren</string>
|
||||
@@ -433,7 +452,7 @@
|
||||
<string name="about__privacy_policy__title" comment="Preference title">Datenschutzrichtlinie</string>
|
||||
<string name="about__privacy_policy__summary" comment="Preference summary">Datenschutzrichtlinie für dieses Projekt</string>
|
||||
<string name="about__project_license__title" comment="Preference title">Projekt-Lizenz</string>
|
||||
<string name="about__project_license__summary" comment="Preference summary">FlorisBoard ist unter {license_name} lizensiert</string>
|
||||
<string name="about__project_license__summary" comment="Preference summary">FlorisBoard ist unter {license_name} lizenziert</string>
|
||||
<string name="about__project_license__error_license_text_failed" comment="Error text for license text loading failure">Fehler: Lizenztext konnte nicht geladen werden.\n-> Grund: {error_message}</string>
|
||||
<string name="about__project_license__error_reason_asset_manager_null" comment="Error text if asset manager is null">Assetmanager Referenz ist null</string>
|
||||
<string name="about__third_party_licenses__title" comment="Preference title">Drittanbieter-Lizenzen</string>
|
||||
@@ -574,7 +593,16 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Sichere Android-Einstellungen</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Android System-Einstellungen</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Systemgebietsschemata</string>
|
||||
<string name="devtools__debuglog__title">Debug Log</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">Debug Log wurde in die Zwischenablage kopiert</string>
|
||||
<string name="devtools__debuglog__copy_log">Log kopieren</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Log kopieren (GitHub Formatierung)</string>
|
||||
<string name="devtools__debuglog__loading">Lädt…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Add-ons & Erweiterungen</string>
|
||||
<string name="ext__list__ext_theme">Design-Erweiterungen</string>
|
||||
<string name="ext__list__ext_keyboard">Tastatur-Erweiterungen</string>
|
||||
<string name="ext__list__ext_languagepack">Sprachpaket-Erweiterungen</string>
|
||||
<string name="ext__meta__authors">Ersteller</string>
|
||||
<string name="ext__meta__components">Gebündelte Komponenten</string>
|
||||
<string name="ext__meta__components_theme">Enthaltene Designs</string>
|
||||
@@ -627,6 +655,40 @@
|
||||
<string name="ext__import__file_skip_ext_not_supported" comment="Reason string when file is loaded in incorrect context">Eine Mediendatei (Bild, Audio, Text, etc.) wurde erwartet, aber ein Erweiterungsarchiv wurde gefunden.</string>
|
||||
<string name="ext__import__file_skip_media_not_supported" comment="Reason string when file is loaded in incorrect context">Ein Erweiterungsarchiv wurde erwartet, aber eine Mediendatei (Bild, Audio, Text, etc.) wurde gefunden.</string>
|
||||
<string name="ext__import__error_unexpected_exception" comment="Label when an error occurred during import. The error message will be appended below this text view">Beim Import ist ein unerwarteter Fehler aufgetreten. Folgende Angaben wurden gemacht:</string>
|
||||
<string name="ext__validation__enter_package_name">Bitte gib einen Paketnamen ein</string>
|
||||
<string name="ext__validation__error_package_name">Paketname stimmt nicht mit Regex {id_regex} überein</string>
|
||||
<string name="ext__validation__enter_version">Bitte gib eine Version an</string>
|
||||
<string name="ext__validation__enter_title">Bitte gib einen Titel ein</string>
|
||||
<string name="ext__validation__enter_maintainer">Bitte gib mindestens einen gültigen Maintainer an</string>
|
||||
<string name="ext__validation__enter_license">Bitte gib eine Lizenzbezeichnung an</string>
|
||||
<string name="ext__validation__enter_component_id">Bitte gib eine Komponenten-ID ein</string>
|
||||
<string name="ext__validation__error_component_id">Bitte eine Komponenten-ID eingeben, welche zu {component_id_regex} passt</string>
|
||||
<string name="ext__validation__enter_component_label">Bitte gib eine Komponentenbezeichnung ein</string>
|
||||
<string name="ext__validation__hint_component_label_to_long">Die Komponentenbezeichnung ist recht lang, was zu einem Abschneiden auf der Benutzeroberfläche führen kann</string>
|
||||
<string name="ext__validation__error_author">Bitte gib mindestens einen gültigen Autor an</string>
|
||||
<string name="ext__validation__error_stylesheet_path_blank">Der Stylesheet-Pfad darf nicht leer sein</string>
|
||||
<string name="ext__validation__error_stylesheet_path">Bitte einen Stylesheet-Pfad eingeben, welcher zu {stylesheet_path_regex} passt</string>
|
||||
<string name="ext__validation__enter_property">Bitte gib einen Variablennamen an</string>
|
||||
<string name="ext__validation__error_property">Bitte einen gültigen Variablennamen eingeben, welcher zu {variable_name_regex} passt</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">Nach FlorisCSS-Konvention beginnt ein Variablenname mit zwei Bindestrichen (--)</string>
|
||||
<string name="ext__validation__enter_color">Bitte gib einen Farbstring ein</string>
|
||||
<string name="ext__validation__error_color">Bitte gib einen gültigen Farbstring ein</string>
|
||||
<string name="ext__validation__enter_dp_size">Bitte gib eine dp-Größe an</string>
|
||||
<string name="ext__validation__enter_valid_number">Bitte gib eine gültige Nummer ein</string>
|
||||
<string name="ext__validation__enter_positive_number">Bitte gib eine positive Zahl ein (>=0)</string>
|
||||
<string name="ext__validation__enter_percent_size">Bitte gib eine Prozentzahl an</string>
|
||||
<string name="ext__validation__enter_number_between_0_100">Bitte gib eine positive Zahl zwischen 0 und 100 an</string>
|
||||
<string name="ext__validation__hint_value_above_50_percent">Jeder Wert über 50 % verhält sich so, als ob 50 % eingestellt wären. Überlege den Wert zu senken</string>
|
||||
<string name="ext__update_box__internet_permission_hint">Weil diese App keine Internetberechtigungen hat, muss manuell nach Updates für Erweiterungen gesucht werden.</string>
|
||||
<string name="ext__update_box__search_for_updates">Nach Updates suchen</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">Verwalte {extensions}</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">Alle Aufgaben im Zusammenhang mit dem Importieren, Exportieren, Erstellen, Anpassen und Entfernen von Erweiterungen können über den Add-on-Manager abgewickelt werden.</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Gehe zu {ext_home_title}</string>
|
||||
<string name="ext__home__info">Erweiterungen können über den FlorisBoard Add-on Store heruntergeladen und installiert werden oder importiere beliebige Erweiterungen aus dem Internet.</string>
|
||||
<string name="ext__home__visit_store">Besuche den Add-ons Store</string>
|
||||
<string name="ext__home__manage_extensions">Installierte Erweiterungen verwalten</string>
|
||||
<string name="ext__list__view_details">Details anzeigen</string>
|
||||
<string name="ext__check_updates__title">Auf Updates prüfen</string>
|
||||
<!-- Action strings -->
|
||||
<string name="action__add">Hinzufügen</string>
|
||||
<string name="action__apply">Übernehmen</string>
|
||||
@@ -694,6 +756,14 @@
|
||||
<string name="enum__display_language_names_in__system_locale__description" comment="Enum value description">Sprachnamen in der App und in der Tastatur werden in der Systemsprache des Geräts dargestellt</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">Systemsprache</string>
|
||||
<string name="enum__display_language_names_in__native_locale__description" comment="Enum value description">Sprachnamen in der App und in der Tastatur werden in der referenzierten Sprache dargestellt</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend" comment="Enum value label">Automatisch Sortieren (Voranstellen)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend__description" comment="Enum value description">Emojis werden bei Verwendung neu sortiert. Neue Emojis werden am Anfang hinzugefügt.</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append" comment="Enum value label">Automatisch Sortieren (Anhängen)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append__description" comment="Enum value description">Emojis werden bei Verwendung neu sortiert. Neue Emojis werden am Ende hinzugefügt.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend" comment="Enum value label">Manuelles Sortieren (Voranstellen)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend__description" comment="Enum value description">Emojis werden bei Verwendung nicht neu sortiert. Neue Emojis werden am Anfang hinzugefügt.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append" comment="Enum value label">Manuelles Sortieren (Anhängen)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append__description" comment="Enum value description">Emojis werden bei Verwendung nicht neu sortiert. Neue Emojis werden am Ende hinzugefügt.</string>
|
||||
<string name="enum__emoji_skin_tone__default" comment="Enum value label">{emoji} Standard Hautfarbe</string>
|
||||
<string name="enum__emoji_skin_tone__light_skin_tone" comment="Enum value label">{emoji} Helle Hautfarbe</string>
|
||||
<string name="enum__emoji_skin_tone__medium_light_skin_tone" comment="Enum value label">{emoji} Mittel helle Hautfarbe</string>
|
||||
@@ -705,6 +775,10 @@
|
||||
<string name="enum__emoji_hair_style__curly_hair" comment="Enum value label">{emoji} Lockige Haare</string>
|
||||
<string name="enum__emoji_hair_style__white_hair" comment="Enum value label">{emoji} Weiße Haare</string>
|
||||
<string name="enum__emoji_hair_style__bald" comment="Enum value label">{emoji} Glatze</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon">Führender Doppelpunkt</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon__description" comment="Keep the :emoji_name while translating, this is a syntax guide">Emojis mit der Syntax :emoji_name vorschlagen</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text">Eingebetteter Text</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text__description">Schlage Emojis vor, indem einfach der Emoji-Namen als Wort eingeben wird</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates" comment="Enum value label">Über Kandidaten</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates__description" comment="Enum value description">Platziert die erweiterte Aktionsleiste zwischen der App-Oberfläche und der Kandidatenleiste</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates" comment="Enum value label">Unter Kandidaten</string>
|
||||
@@ -820,4 +894,12 @@
|
||||
<item quantity="one">{v} Element</item>
|
||||
<item quantity="other">{v} Elemente</item>
|
||||
</plurals>
|
||||
<plurals name="unit__characters__written">
|
||||
<item quantity="one">{v} Zeichen</item>
|
||||
<item quantity="other">{v} Zeichen</item>
|
||||
</plurals>
|
||||
<plurals name="unit__candidates__written">
|
||||
<item quantity="one">{v} Vorschlag</item>
|
||||
<item quantity="other">{v} Vorschläge</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Εικονίδια Emoji</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Εικονίδια emoticon</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Μέγιστο μέγεθος ιστορικού εικονιδίων emoji</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Προτιμώμενος τόνος επιδερμίδας εικονιδίων emoji</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Φατσούλες & Συναισθήματα</string>
|
||||
|
||||
@@ -13,9 +13,18 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojis</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticonos</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Tamaño máximo de historial de emojis</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Tono de piel de emoji preferido</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Estilo de cabello de emoji preferido</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Sugerencias de emoticonos</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Habilitar sugerencias de emoticonos</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Proporcionar sugerencias de emoticonos mientras escribes</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Tipo de acción</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Actualizar el historial de emoticonos</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Al aceptar emoticonos sugeridos, se añaden al historial de emoticonos</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Muestra el nombre de emoticono</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Las sugerencias de emoticono muestran su nombre junto al emoticono</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Longitud mínima de consulta</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Número máximo de candidatos</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smileys & Emociones</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Personas & Cuerpo</string>
|
||||
@@ -26,20 +35,25 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objetos</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Símbolos</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Banderas</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">No se han encontrado emojis que se hayan usado recientemente. Una vez empieces a usar emojis, aparecerán automáticamente aquí.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Para acceder a tu historial de emojis, por favor, desbloquea primero tu dispositivo.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Consejo: ¡Pulse sostenidamente los emojis usados recientemente para poder removerlos de esta vista!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Se ha removido {emoji} de los emojis recientes</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Arriba</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Realizar flecha hacia arriba</string>
|
||||
<string name="quick_action__arrow_down" maxLength="12">Abajo</string>
|
||||
<string name="quick_action__arrow_down__tooltip">Realizar flecha hacia abajo</string>
|
||||
<string name="quick_action__arrow_left" maxLength="12">Izquierda</string>
|
||||
<string name="quick_action__arrow_left__tooltip">Realizar flecha hacia la izquierda</string>
|
||||
<string name="quick_action__arrow_right" maxLength="12">Derecha</string>
|
||||
<string name="quick_action__arrow_right__tooltip">Realizar flecha hacia la derecha</string>
|
||||
<string name="quick_action__clipboard_clear_primary_clip" maxLength="12">Borrar clip</string>
|
||||
<string name="quick_action__clipboard_clear_primary_clip__tooltip">Realizar limpiar portapapeles principal</string>
|
||||
<string name="quick_action__clipboard_copy" maxLength="12">Copiar</string>
|
||||
<string name="quick_action__clipboard_copy__tooltip">Realizar copiar portapapeles</string>
|
||||
<string name="quick_action__clipboard_cut" maxLength="12">Cortar</string>
|
||||
<string name="quick_action__clipboard_cut__tooltip">Realizar cortar portapapeles</string>
|
||||
<string name="quick_action__clipboard_paste" maxLength="12">Pegar</string>
|
||||
<string name="quick_action__clipboard_paste__tooltip">Realizar pegar portapapeles</string>
|
||||
<string name="quick_action__clipboard_select_all" maxLength="12">Seleccionar</string>
|
||||
<string name="quick_action__clipboard_select_all__tooltip">Realizar seleccionar todo en portapapeles</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard" maxLength="12">Portapapeles</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard__tooltip">Abrir historial del portapapeles</string>
|
||||
<string name="quick_action__ime_ui_mode_media" maxLength="12">Emoji</string>
|
||||
@@ -115,6 +129,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Al menos un campo no posee un valor seleccionado. Por favor escoja un valor para el(los) campo(s).</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (no instalado)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Distribuciones</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Confirmación de eliminación</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">¿Está seguro de que desea eliminar este subtipo?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Tema</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Tema</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Amanecer</string>
|
||||
@@ -138,6 +154,7 @@
|
||||
<string name="settings__theme_editor__rule_element">Elemento destino</string>
|
||||
<string name="settings__theme_editor__rule_codes">Códigos de clave destino</string>
|
||||
<string name="settings__theme_editor__rule_groups">Grupos</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Cambiar estados</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Selectores</string>
|
||||
<string name="settings__theme_editor__add_code">Añadir código clave</string>
|
||||
<string name="settings__theme_editor__edit_code">Editar código clave</string>
|
||||
@@ -176,11 +193,23 @@
|
||||
<string name="snygg__rule_element__emoji_key_tab">Pestaña de emojis</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Disposición de la entrada del paisaje</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Campo de entrada en paisaje</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Acción de entrada apaisada</string>
|
||||
<string name="snygg__rule_element__glide_trail">Rastro del gesto</string>
|
||||
<string name="snygg__rule_element__incognito_mode_indicator">Indicador de modo incógnito</string>
|
||||
<string name="snygg__rule_element__one_handed_panel">Panel a una mano</string>
|
||||
<string name="snygg__rule_element__smartbar">Barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_row">Fila de acciones compartidas de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_toggle">Alternar acciones compartidas de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_row">Fila de acciones extendidas de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_toggle">Alternar acciones extendidas de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_action_key">Tecla de acción de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_action_tile">Mosaico de acción de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_overflow">Acciones de overflow de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_overflow_customize_button">Botón de personalización de overflow de acciones de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_editor">Editor de acciones de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_editor_header">Cabecera del editor de acciones de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_editor_subheader">Subencabezado del editor de acciones de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidates_row">Fila de candidatos de la barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Palabra candidata de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Clip candidato de barra inteligente</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">Espaciado candidato de barra inteligente</string>
|
||||
@@ -234,6 +263,7 @@
|
||||
<string name="settings__input_feedback__title" comment="Title of Input Feedback screen">Sonidos & Vibración</string>
|
||||
<string name="pref__input_feedback__group_audio__label" comment="Preference group title">Respuesta de audio / Sonidos</string>
|
||||
<string name="pref__input_feedback__audio_enabled__label" comment="Preference title">Habilitar respuesta de audio</string>
|
||||
<string name="pref__input_feedback__audio_enabled__summary_disabled" comment="Preference summary">No reproducir nunca sonidos para eventos de entrada, independientemente de la configuración del sistema</string>
|
||||
<string name="pref__input_feedback__audio_volume__label" comment="Preference title">Volumen de sonido para eventos de entrada</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_press__label" comment="Preference title">Sonidos al presionar una tecla</string>
|
||||
<string name="pref__input_feedback__audio_feat_key_long_press__label" comment="Preference title">Sonidos al presionar prolongadamente</string>
|
||||
@@ -242,6 +272,7 @@
|
||||
<string name="pref__input_feedback__audio_feat_gesture_moving_swipe__label" comment="Preference title">Sonidos de gestos deslizantes con movimiento</string>
|
||||
<string name="pref__input_feedback__group_haptic__label" comment="Preference group title">Respuesta táctil / Vibración</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__label" comment="Preference title">Habilitar respuesta táctil</string>
|
||||
<string name="pref__input_feedback__haptic_enabled__summary_disabled" comment="Preference summary">Nunca vibrar por eventos de entrada, independientemente de la configuración del sistema</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_mode__label" comment="Preference title">Modo de vibración</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_duration__label" comment="Preference title">Duración de vibración</string>
|
||||
<string name="pref__input_feedback__haptic_vibration_strength__label" comment="Preference title">Intensidad de vibración</string>
|
||||
@@ -266,6 +297,8 @@
|
||||
<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>
|
||||
<string name="pref__keyboard__space_bar_mode__label" comment="Preference title">Etiqueta de la barra espaciadora</string>
|
||||
<string name="pref__keyboard__capitalization_behavior__label" comment="Preference title">Comportamiento de las mayúsculas</string>
|
||||
<string name="pref__keyboard__font_size_multiplier__label" comment="Preference title">Multiplicador del tamaño de fuente</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 title">Modo a una mano</string>
|
||||
@@ -385,6 +418,7 @@
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Claro</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Oscuro</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Oscuro</string>
|
||||
<string name="pref__advanced__settings_material_you__label" comment="Label of Material You preference in Advanced">Usar material tú</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Idioma de ajustes</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Mostrar icono de la aplicación en el launcher</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Habilitado siempre en Android 10+ debido a restricciones del sistema</string>
|
||||
@@ -422,6 +456,12 @@
|
||||
<string name="setup__select_ime__title">Seleccionar {app_name}</string>
|
||||
<string name="setup__select_ime__description">{app_name} está ahora habilitado en su sistema. ¡Para usarlo activamente cambie a {app_name} seleccionándolo en el diálogo del selector de entrada!</string>
|
||||
<string name="setup__select_ime__switch_keyboard_btn">Cambiar teclado</string>
|
||||
<string name="setup__grant_notification_permission__title">Permitir notificaciones de informes de errores</string>
|
||||
<string name="setup__grant_notification_permission__description">A partir de Android 13+, las aplicaciones deben pedir permiso para
|
||||
enviar notificaciones. En Florisboard, esto solo se utiliza para abrir una pantalla de informe de error en caso de error.
|
||||
Este permiso puede cambiarse en cualquier momento en los ajustes del sistema.
|
||||
</string>
|
||||
<string name="setup__grant_notification_permission__btn">Conceder permiso</string>
|
||||
<string name="setup__finish_up__title">Finalizar</string>
|
||||
<string name="setup__finish_up__description_p1">{app_name} ahora está habilitado en su sistema y listo para ser personalizado.</string>
|
||||
<string name="setup__finish_up__description_p2">Si encuentra algún problema, errores, fallos o sólo desea hacer alguna sugerencia, ¡revise el repositorio del proyecto en el menú de \"Acerca de\"!</string>
|
||||
@@ -438,6 +478,7 @@
|
||||
<string name="backup_and_restore__back_up__files_ime_keyboard">Extensiones del teclado</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_spelling">Extensiones de corrección ortográfica / diccionarios</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_theme">Extensiones de temas</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history">Historial del portapapeles</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_text_items">Ítems de texto</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_image_items">Imágenes</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_video_items">Vídeos</string>
|
||||
@@ -514,6 +555,8 @@
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__summary">Al borrar el clip principal también se borra la última entrada del historial</string>
|
||||
<string name="send_to_clipboard__unknown_error">Ha ocurrido un error desconocido. Por favor, vuelve a intentarlo.</string>
|
||||
<string name="send_to_clipboard__type_not_supported_error">Este tipo de medio no está soportado.</string>
|
||||
<string name="send_to_clipboard__android_version_to_old_error">La versión de android es demasiado antigua para esta función.</string>
|
||||
<string name="send_to_clipboard__description__copied_image_to_clipboard">Imagen copiada en el portapapeles.</string>
|
||||
<!-- Devtools strings -->
|
||||
<string name="devtools__title" comment="Title of Devtools screen. Translators: treat this string as 'Developer tools' for translation, except a similar short term is available for your language.">Herramientas de desarrollo</string>
|
||||
<string name="devtools__enabled__label" comment="Label of Enable developer tools in Devtools">Habilitar herramientas de desarrollador</string>
|
||||
@@ -541,6 +584,11 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Ajustes Secure de Android</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Ajustes System de Android</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Regiones del sistema</string>
|
||||
<string name="devtools__debuglog__title">Registro de depuración</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">Registro de depuración copiado en el portapapeles</string>
|
||||
<string name="devtools__debuglog__copy_log">Copiar registro</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Copiar registro (formato GitHub)</string>
|
||||
<string name="devtools__debuglog__loading">Cargando…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__meta__authors">Autores</string>
|
||||
<string name="ext__meta__components">Componentes agrupados</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">شکلکها</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticons</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">حداکثر حجم تاریخچه ایموجی</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">رنگ پوست پیشفرض برای ایموجی</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">مدل مو پیشفرض برای ایموجی</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,10 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">اشیاء</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">نمادها</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">پرچم ها</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">ایموجی استفاده شده ای یافت نشد. زمانی که شروع به نوشتن ایموجی ها بکنید به صورت خودکار اینجا ظاهر خواهند شد.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">برای دسترسی به تاریخ صورتکها گوشیتان باز کنید.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">توصیه کاربردی: روی ایموجی های استفاده شده نگهدارید تا آن ها را از اینجا حذف کنید!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">ایموجی {emoji} از ایموجی های اخیرا استفاده شده حذف شد</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">فلش بالا</string>
|
||||
<string name="quick_action__arrow_up__tooltip">فلش به سمت بالا</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojit</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Hymiöt</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomojit</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Emojihistorian maksimikoko</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Emojien oletusihonväri</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Emojien oletushiustyyli</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,9 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Esineet</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symbolit</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Liput</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Viimeaikaisia emojeja ei löytynyt. Kun käytät emojeja, ne näytetään automaattisesti täällä.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro tip: Paina emojia pitkään poistaaksesi sen tästä näkymästä!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Poistettu {emoji} viimeaikaisista emojeista</string>
|
||||
<!-- Quick action strings -->
|
||||
<!-- Incognito mode strings -->
|
||||
<!-- Settings UI strings -->
|
||||
|
||||
@@ -13,9 +13,18 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Émojis</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Émoticônes</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Taille maximum de l\'historique d\'émojis</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Couleur de peau des émojis par défaut</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Cheveux des émojis par défaut</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Suggestions d\'émoji</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">Activer les suggestions d\'émoji</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled__summary" comment="Preference summary">Fournit des suggestions d\'émoji lors de la saisie</string>
|
||||
<string name="prefs__media__emoji_suggestion_type" comment="Preference title">Type de déclencheur</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">Mettre à jour l\'historique émoji</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history__summary" comment="Preference summary">Ajoute les émojis suggérés et acceptés à l\'historique</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">Afficher le nom de l\'émoji</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name__summary" comment="Preference summary">Affiche le nom des suggestions d\'émoji à côté de l\'émoji</string>
|
||||
<string name="prefs__media__emoji_suggestion_query_min_length" comment="Preference title">Longueur minimale de la requête</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_max_count" comment="Preference title">Nombre maximal de candidats</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smileys & Émotions</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Personnes & Corps</string>
|
||||
@@ -26,10 +35,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objets</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symboles</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Drapeaux</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Aucun émoji récemment utilisé n\'a été trouvé. Une fois que vous aurez commencé à taper des émojis, ils apparaîtront automatiquement ici.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Pour accéder à l\'historique emoji, veuillez d\'abord déverrouiller votre appareil.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Conseil de pro : appuyez longuement sur les émojis récemment utilisés pour les supprimer à nouveau de cette vue !</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Suppression de {emoji} des emojis récemment utilisés</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Flèche haut</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Appui sur la flèche haut</string>
|
||||
@@ -124,6 +129,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Au moins un champ n\'a pas de valeur sélectionnée. Veuillez choisir une valeur pour le(s) champ(s).</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (non installé)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Dispositions</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Confirmer la suppression</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">Êtes-vous sûr de vouloir supprimer ce sous-type ?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Thème</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Mode du thème</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Heure de lever du soleil</string>
|
||||
@@ -565,6 +572,8 @@
|
||||
<string name="devtools__show_input_state_overlay__summary" comment="Summary of Show input cache overlay in Devtools">Superpose l\'état actuel de l\'entrée pour le débogage</string>
|
||||
<string name="devtools__show_spelling_overlay__label" comment="Label of Show spelling overlay in Devtools">Afficher la superposition d\'orthographe</string>
|
||||
<string name="devtools__show_spelling_overlay__summary" comment="Summary of Show spelling overlay in Devtools">Superpose les résultats d\'orthographe actuels pour le débogage</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__label">Superposer l\'autocomplétion sur la ligne</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__summary">Superpose les résultats d\'orthographe actuels pour le débogage</string>
|
||||
<string name="devtools__show_key_touch_boundaries__label" comment="Label of Show key touch boundaries in Devtools">Afficher les limites des touches</string>
|
||||
<string name="devtools__show_key_touch_boundaries__summary" comment="Summary of Show key touch boundaries in Devtools">Soulignez en rouge les limites des touches clés</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">Afficher les aides de glisser-déposer</string>
|
||||
@@ -580,6 +589,11 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Paramètres de sécurité Android</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Paramètres système Android</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Paramètres régionaux du système</string>
|
||||
<string name="devtools__debuglog__title">Journal de débogage</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">Journal de débogage copié dans le presse-papiers</string>
|
||||
<string name="devtools__debuglog__copy_log">Copier le journal</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Copier le journal (formatage GitHub)</string>
|
||||
<string name="devtools__debuglog__loading">Chargement…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Modules & Extensions</string>
|
||||
<string name="ext__list__ext_theme">Extensions de thème</string>
|
||||
@@ -749,6 +763,10 @@
|
||||
<string name="enum__emoji_hair_style__curly_hair" comment="Enum value label">{emoji} Cheveux frisés</string>
|
||||
<string name="enum__emoji_hair_style__white_hair" comment="Enum value label">{emoji} Cheveux blanc</string>
|
||||
<string name="enum__emoji_hair_style__bald" comment="Enum value label">{emoji} Chauve</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon">Deux points</string>
|
||||
<string name="enum__emoji_suggestion_type__leading_colon__description" comment="Keep the :emoji_name while translating, this is a syntax guide">Suggère des émojis en utilisant la syntaxe :nom</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text">Intégré au texte</string>
|
||||
<string name="enum__emoji_suggestion_type__inline_text__description">Suggère des émojis en tapant simplement son nom comme mot</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates" comment="Enum value label">Suggestions ci-dessus</string>
|
||||
<string name="enum__extended_actions_placement__above_candidates__description" comment="Enum value description">Place la rangée des actions étendues entre l\'interface utilisateur de l\'application et la rangée des suggestions</string>
|
||||
<string name="enum__extended_actions_placement__below_candidates" comment="Enum value label">Les suggestions ci-dessous</string>
|
||||
@@ -864,4 +882,8 @@
|
||||
<item quantity="one">{v} élément</item>
|
||||
<item quantity="other">{v} éléments</item>
|
||||
</plurals>
|
||||
<plurals name="unit__characters__written">
|
||||
<item quantity="one">{v} caractère</item>
|
||||
<item quantity="other">{v} caractères</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emotikoni</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emotikoni</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaoemotikoni</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Prikazana povijest korištenih emotikona je maksimalna</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Željeni ton boje emotikona</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Željeni stil frizure emotikona</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,9 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objekti</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Simboli</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Zastave</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Nema nedavno korištenih emotikona. Čim ih počnete koristiti, oni će se pojaviti ovdje.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro savjet: Dugo držite nedavno korištene emotikone kako bi ste ih uklonili sa popisa nedavno korištenih emotikona!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji} je ukonjen iz nedavno korištenih emotikona</string>
|
||||
<!-- Quick action strings -->
|
||||
<!-- Incognito mode strings -->
|
||||
<!-- Settings UI strings -->
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
<string name="one_handed__move_start_btn_content_description" comment="Content description for the one-handed move to left button">Billentyűzet balra helyezése.</string>
|
||||
<string name="one_handed__move_end_btn_content_description" comment="Content description for the one-handed move to right button">Billentyűzet jobbra helyezése.</string>
|
||||
<!-- Media strings -->
|
||||
<string name="settings__media__title">Emojik</string>
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojik</string>
|
||||
<string name="settings__media__title">Emodzsik</string>
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emodzsik</string>
|
||||
<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>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Emojielőzmények maximális mérete</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Előnyben részesített emoji-bőrszín</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Előnyben részesített emoji hajstílus</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomodzsi</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Emodzsik előnyben részesített bőrszíne</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Emodzsik előnyben részesítet hajstílusa</string>
|
||||
<!-- Emoji strings -->
|
||||
<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>
|
||||
@@ -26,10 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Tárgyak</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Szimbólumok</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Zászlók</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Nem található mostanában használt emoji. Az emojik automatikusan megjelennek itt, amint elkezdi őket beírni.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">A hangulatjel előzmények eléréséhez, kérjük először oldja fel a készülékét.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Profi tipp: nyomjon hosszan a mostanában használt emojikra, hogy eltávolítsa őket ebből a nézetből!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji} eltávolítva a mostanában használt emojik közül</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Felfele nyíl</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Felfelé nyíl végrehajtása</string>
|
||||
@@ -40,37 +35,37 @@
|
||||
<string name="quick_action__arrow_right" maxLength="12">Jobbra nyíl</string>
|
||||
<string name="quick_action__arrow_right__tooltip">Jobbra nyíl végrehajtása</string>
|
||||
<string name="quick_action__clipboard_clear_primary_clip" maxLength="12">Vágólapürítő</string>
|
||||
<string name="quick_action__clipboard_clear_primary_clip__tooltip">Elsődleges vágólap ürítés végrehajtása</string>
|
||||
<string name="quick_action__clipboard_clear_primary_clip__tooltip">Elsődleges vágólap ürítésének végrehajtása</string>
|
||||
<string name="quick_action__clipboard_copy" maxLength="12">Másolás</string>
|
||||
<string name="quick_action__clipboard_copy__tooltip">Vágólapi másolás végrehajtása</string>
|
||||
<string name="quick_action__clipboard_copy__tooltip">Vágólapra másolás végrehajtása</string>
|
||||
<string name="quick_action__clipboard_cut" maxLength="12">Kivágás</string>
|
||||
<string name="quick_action__clipboard_cut__tooltip">Vágólapi kivágás végrehajtása</string>
|
||||
<string name="quick_action__clipboard_cut__tooltip">Vágólapra kivágás végrehajtása</string>
|
||||
<string name="quick_action__clipboard_paste" maxLength="12">Beillesztés</string>
|
||||
<string name="quick_action__clipboard_paste__tooltip">Vágólapi beillesztés végrehajtása</string>
|
||||
<string name="quick_action__clipboard_paste__tooltip">Vágólapról beillesztés végrehajtása</string>
|
||||
<string name="quick_action__clipboard_select_all" maxLength="12">Mind kijelöl</string>
|
||||
<string name="quick_action__clipboard_select_all__tooltip">Összes kijelölése vágólapra végrehajtása</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard" maxLength="12">Vágólap</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard__tooltip">Vágólapelőzmények megnyitása</string>
|
||||
<string name="quick_action__ime_ui_mode_media" maxLength="12">Hangulatjel</string>
|
||||
<string name="quick_action__ime_ui_mode_media__tooltip">Hangulatjel panel megnyitása</string>
|
||||
<string name="quick_action__ime_ui_mode_clipboard__tooltip">Vágólap-előzmények megnyitása</string>
|
||||
<string name="quick_action__ime_ui_mode_media" maxLength="12">Emodzsi</string>
|
||||
<string name="quick_action__ime_ui_mode_media__tooltip">Emodzsi panel megnyitása</string>
|
||||
<string name="quick_action__settings" maxLength="12">Beállítások</string>
|
||||
<string name="quick_action__settings__tooltip">Beállítások megnyitása</string>
|
||||
<string name="quick_action__undo" maxLength="12">Visszavonás</string>
|
||||
<string name="quick_action__undo__tooltip">Utolsó változás visszavonása</string>
|
||||
<string name="quick_action__undo__tooltip">Utolsó bemenet visszavonása</string>
|
||||
<string name="quick_action__redo" maxLength="12">Újra</string>
|
||||
<string name="quick_action__redo__tooltip">Visszavonás törlése</string>
|
||||
<string name="quick_action__redo__tooltip">Utolsó bemenet újbóli beírása</string>
|
||||
<string name="quick_action__toggle_actions_overflow" maxLength="12">Továbbiak</string>
|
||||
<string name="quick_action__toggle_actions_overflow__tooltip">További műveletek megjelenítése vagy elrejtése</string>
|
||||
<string name="quick_action__toggle_incognito_mode" maxLength="12">Inkognitó</string>
|
||||
<string name="quick_action__toggle_incognito_mode__tooltip">Inkognitó mód bekapcsolása</string>
|
||||
<string name="quick_action__toggle_autocorrect" maxLength="12">Auto-korrekt</string>
|
||||
<string name="quick_action__toggle_autocorrect__tooltip">Automatikus javítás váltása</string>
|
||||
<string name="quick_action__toggle_autocorrect__tooltip">Automatikus javítás be/ki</string>
|
||||
<string name="quick_action__voice_input" maxLength="12">Hangbevitel</string>
|
||||
<string name="quick_action__voice_input__tooltip" comment="IME stands for Input Method Editor and is indirectly equivalent to 'keyboard'.">Hangbevitel szolgáltató megnyitása</string>
|
||||
<string name="quick_action__voice_input__tooltip" comment="IME stands for Input Method Editor and is indirectly equivalent to 'keyboard'.">Hangbevitel szolgáltatójának megnyitása</string>
|
||||
<string name="quick_action__one_handed_mode" maxLength="12">Egykezes</string>
|
||||
<string name="quick_action__one_handed_mode__tooltip">Egykezes mód váltása</string>
|
||||
<string name="quick_action__drag_marker" maxLength="12" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Húzás jelölő</string>
|
||||
<string name="quick_action__drag_marker__tooltip" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Jelenlegi kurzor mozgató pozíció</string>
|
||||
<string name="quick_action__one_handed_mode__tooltip">Egykezes mód be/ki</string>
|
||||
<string name="quick_action__drag_marker" maxLength="12" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Húzásjelölő</string>
|
||||
<string name="quick_action__drag_marker__tooltip" comment="This action is only used as a placeholder in the actions editor drag and drop screen and only visible in debug mode">Jelenlegi húzásjelölő pozíciója</string>
|
||||
<string name="quick_action__noop" maxLength="12" comment="Noop=no operation; this action is only used as a placeholder in the actions editor drag and drop screen">Semmi</string>
|
||||
<string name="quick_action__noop__tooltip" comment="Noop=no operation; this action is only used as a placeholder in the actions editor drag and drop screen">Nincs művelet</string>
|
||||
<string name="quick_actions_overflow__customize_actions_button">Műveletek átrendezése</string>
|
||||
@@ -79,17 +74,17 @@
|
||||
<string name="quick_actions_editor__subheader_dynamic_actions">Dinamikus műveletek ({n})</string>
|
||||
<string name="quick_actions_editor__subheader_hidden_actions">Elrejtett műveletek ({n})</string>
|
||||
<!-- Incognito mode strings -->
|
||||
<string name="incognito_mode__toast_after_enabled">Az inkognitó mód bekapcsolva\n\n{app_name} nem fog tanulni a beírt szavakból, amíg ez a mód aktív</string>
|
||||
<string name="incognito_mode__toast_after_enabled">Az inkognitó mód bekapcsolva\n\nA {app_name} nem fog tanulni a beírt szavakból, amíg ez a mód aktív</string>
|
||||
<string name="incognito_mode__toast_after_disabled">Az inkognitó mód mostantól alapértelmezés szerint ki van kapcsolva</string>
|
||||
<!-- Settings UI strings -->
|
||||
<string name="settings__title" comment="Title of Settings">Beállítások</string>
|
||||
<string name="settings__preview_keyboard" comment="Hint for try your setup box">Próbálja ki a beállításait</string>
|
||||
<string name="settings__help" comment="General label for help buttons in Settings">Súgó</string>
|
||||
<string name="settings__default" comment="General string which is used when a preference has the default value set">Alapértelmezett</string>
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">Rendszer alapértelmezett</string>
|
||||
<string name="settings__home__title" comment="Title of the Home screen">A {app_name} üdvözli</string>
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">FlorisBoard nincs engedélyezve a rendszerben, így nem lesz elérhető beviteli módszerként a bevitelválasztóban. A probléma megoldásához kattintson ide.</string>
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">A FlorisBoard nincs kiválasztva alapértelmezett beviteli módszerként. A probléma megoldásához kattintson ide.</string>
|
||||
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">Rendszer alapértelmezése</string>
|
||||
<string name="settings__home__title" comment="Title of the Home screen">Üdvözli a {app_name}</string>
|
||||
<string name="settings__home__ime_not_enabled" comment="Error message shown in Home fragment when FlorisBoard is not enabled in the system">A FlorisBoard nincs engedélyezve a rendszerben, így nem lesz elérhető beviteli módként a bevitelválasztóban. A probléma megoldásához kattintson ide.</string>
|
||||
<string name="settings__home__ime_not_selected" comment="Warning message shown in Home fragment when FlorisBoard is not selected as the default keyboard">Nem a FlorisBoard az alapértelmezett beviteli mód. A probléma megoldásához kattintson ide.</string>
|
||||
<string name="settings__localization__title" comment="Title of languages and Layout screen">Nyelvek és elrendezések</string>
|
||||
<string name="settings__localization__display_language_names_in__label" comment="Label of Display language names in preference">Nyelvek neveinek megjelenítése ebben</string>
|
||||
<string name="settings__localization__group_subtypes__label" comment="Label of subtypes group">Altípusok</string>
|
||||
@@ -104,7 +99,7 @@
|
||||
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">Elsődleges szimbólumelrendezés</string>
|
||||
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">Másodlagos szimbólumelrendezés</string>
|
||||
<string name="settings__localization__subtype_composer" comment="Label for composer dropdown in subtype dialog.">Összeállító</string>
|
||||
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">Pénznem készlet</string>
|
||||
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">Pénznemkészlet</string>
|
||||
<string name="settings__localization__subtype_numeric_layout" comment="Label for layout dropdown in subtype dialog">Számelrendezés</string>
|
||||
<string name="settings__localization__subtype_numeric_advanced_layout" comment="Label for layout dropdown in subtype dialog">(Speciális) számelrendezés</string>
|
||||
<string name="settings__localization__subtype_numeric_row_layout" comment="Label for layout dropdown in subtype dialog">Számsor elrendezése</string>
|
||||
@@ -112,20 +107,22 @@
|
||||
<string name="settings__localization__subtype_phone2_layout" comment="Label for layout dropdown in subtype dialog">Másodlagos telefonelrendezés</string>
|
||||
<string name="settings__localization__subtype_select_locale" comment="Subtype select language title">Nyelv választása</string>
|
||||
<string name="settings__localization__subtype_search_locale_placeholder" comment="Subtype search language placeholder">Nyelv keresése</string>
|
||||
<string name="settings__localization__subtype_search_locale_not_found" comment="Subtype search language not found">Nem sikerült egyező nyelvet találni \"{search_term}\".</string>
|
||||
<string name="settings__localization__subtype_select_placeholder" comment="Subtype dialog select value placeholder (&#8210; is a hyphen character)">‒ &#8210 kiválasztása;</string>
|
||||
<string name="settings__localization__subtype_search_locale_not_found" comment="Subtype search language not found">Nem található ennek megfelelő nyelv: „{search_term}”.</string>
|
||||
<string name="settings__localization__subtype_select_placeholder" comment="Subtype dialog select value placeholder (&#8210; is a hyphen character)">‒ válasszon ‒</string>
|
||||
<string name="settings__localization__subtype_summary" comment="Subtype summary">{characters_name} / {symbols_name} / {currency_set_name}</string>
|
||||
<string name="settings__localization__suggested_subtype_presets" comment="Suggested presets title">Javasolt altípusok sémák</string>
|
||||
<string name="settings__localization__suggested_subtype_presets_none_found" comment="Suggested presets none found">Nem elérhető javasolt séma. Használja a lentebbi gombot az összes altípus séma megtekintéséhez.</string>
|
||||
<string name="settings__localization__subtype_presets" comment="Subtype presets dialog title">Altípus sémák</string>
|
||||
<string name="settings__localization__suggested_subtype_presets" comment="Suggested presets title">Javasolt altípussémák</string>
|
||||
<string name="settings__localization__suggested_subtype_presets_none_found" comment="Suggested presets none found">Nem elérhető javasolt séma. Használja a lentebbi gombot az összes altípusséma megtekintéséhez.</string>
|
||||
<string name="settings__localization__subtype_presets" comment="Subtype presets dialog title">Altípussémák</string>
|
||||
<string name="settings__localization__subtype_presets_view_all" comment="View all presets button">Összes megjelenítése</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">Úgy tűnik, hogy nem állított be altípusokat. Tartalékként az angol/QWERTY lesz használva!</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning" comment="Warning message that no subtype has been defined">Úgy tűnik, hogy nem állított be altípusokat. Tartalékként az angol/QWERTY altípus lesz használva.</string>
|
||||
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Ez az altípus már létezik!</string>
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Legalább egy mezőnek nincs érték kiválasztva. Kérjük válasszon értéket az összes mezőnek.</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (nincs telepítve)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Kiosztások</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Törlés megerősítése</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">Biztosan törli ezt az altípust?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Téma</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Téma mód</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Témamód</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Napkelte ideje</string>
|
||||
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Napnyugta ideje</string>
|
||||
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Nappali téma</string>
|
||||
@@ -135,17 +132,17 @@
|
||||
<string name="pref__theme__source_internal" comment="Label for the theme source field">Belső tárhely</string>
|
||||
<string name="pref__theme__source_external" comment="Label for the theme source field">Külső szolgáltató</string>
|
||||
<string name="settings__theme_manager__title_day" comment="Title of the theme manager screen for day theme selection">Nappali téma kiválasztása</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Éjjeli téma kiválasztása</string>
|
||||
<string name="settings__theme_manager__title_night" comment="Title of the theme manager screen for night theme selection">Éjszakai téma kiválasztása</string>
|
||||
<string name="settings__theme_editor__fine_tune__title">Finomhangoló szerkesztő</string>
|
||||
<string name="settings__theme_editor__fine_tune__level">Szerkesztői szint</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_colors_as">Színek megjelenítése mint</string>
|
||||
<string name="settings__theme_editor__fine_tune__display_kbd_after_dialogs">Billentyűzet megjelenítése párbeszédpanelek után</string>
|
||||
<string name="settings__theme_editor__add_rule">Szabály hozzáadása</string>
|
||||
<string name="settings__theme_editor__edit_rule">Szabály szerkesztése</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">Ennél a stíluslapnál nincsenek definiált szabályok. Adjon hozzá új szabályt a stíluslap testreszabásához.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Ez a stíluslap szabály már korábban meghatározásra került.</string>
|
||||
<string name="settings__theme_editor__rule_element">Cél elem</string>
|
||||
<string name="settings__theme_editor__rule_codes">Cél billentyűkódok</string>
|
||||
<string name="settings__theme_editor__no_rules_defined">A stíluslapnak nincsenek megadott szabályai. Adjon hozzá egy új szabályt a stíluslap testreszabásához.</string>
|
||||
<string name="settings__theme_editor__rule_already_exists">Ez a stíluslapszabály már korábban meg lett adva.</string>
|
||||
<string name="settings__theme_editor__rule_element">Célelem</string>
|
||||
<string name="settings__theme_editor__rule_codes">Célbillentyűkódok</string>
|
||||
<string name="settings__theme_editor__rule_groups">Csoportok</string>
|
||||
<string name="settings__theme_editor__rule_shift_states">Shift állapotok</string>
|
||||
<string name="settings__theme_editor__rule_selectors">Választók</string>
|
||||
@@ -153,7 +150,7 @@
|
||||
<string name="settings__theme_editor__edit_code">Billentyűkód szerkesztése</string>
|
||||
<string name="settings__theme_editor__no_codes_defined">Szabály alkalmazása az összes célelemre.</string>
|
||||
<string name="settings__theme_editor__codes_defined">Szabály alkalmazása csak a következő billentyűkódokkal rendelkező elemekre:</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Ez a billentyűkód már definiálva van.</string>
|
||||
<string name="settings__theme_editor__code_already_exists">Ez a billentyűkód már meg lett adva.</string>
|
||||
<string name="settings__theme_editor__code_invalid">Ez a billentyűkód nem érvényes. Győződjön meg róla, hogy az érték {c_min} és {c_max} között van, vagy {i_min} és {i_max} között a belső speciális billentyűk esetében.</string>
|
||||
<string name="settings__theme_editor__code_help_text">Esetlegesen az alábbi linkek segíteni fognak a megfelelő billentyűkód megtalálásában:</string>
|
||||
<string name="settings__theme_editor__code_placeholder">Kód</string>
|
||||
@@ -164,7 +161,7 @@
|
||||
<string name="settings__theme_editor__code_recording_placeholder">Rögzítés…</string>
|
||||
<string name="settings__theme_editor__add_property">Tulajdonság hozzáadása</string>
|
||||
<string name="settings__theme_editor__edit_property">Tulajdonság szerkesztése</string>
|
||||
<string name="settings__theme_editor__property_already_exists">A jelenlegi szabályon belül egy tulajdonság már létezik ezzel a névvel.</string>
|
||||
<string name="settings__theme_editor__property_already_exists">Már létezik ilyen nevű tulajdonság a jelenlegi szabályban.</string>
|
||||
<string name="settings__theme_editor__property_name">Tulajdonság neve</string>
|
||||
<string name="settings__theme_editor__property_value">Tulajdonság értéke</string>
|
||||
<string name="settings__theme_editor__property_value_shape_apply_for_all_corners">Alkalmazás az összes sarokra</string>
|
||||
@@ -176,26 +173,26 @@
|
||||
<string name="snygg__rule_element__defines_description">Definiálja a szabályon belüli változókat, hogy újrahasználhasson gyakori színeket és sorokat a stíluslapon.</string>
|
||||
<string name="snygg__rule_element__keyboard">Billentyűzetablak</string>
|
||||
<string name="snygg__rule_element__key">Billentyű</string>
|
||||
<string name="snygg__rule_element__key_hint">Billentyű tipp</string>
|
||||
<string name="snygg__rule_element__key_hint">Billentyű eszköztippje</string>
|
||||
<string name="snygg__rule_element__key_popup">Felugró billentyű</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Vágólap fejléc</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Vágólap elem</string>
|
||||
<string name="snygg__rule_element__clipboard_header">Vágólapfejléc</string>
|
||||
<string name="snygg__rule_element__clipboard_item">Vágólapelem</string>
|
||||
<string name="snygg__rule_element__clipboard_item_popup">Felugró vágólapelem</string>
|
||||
<string name="snygg__rule_element__emoji_key">Emodzsi gomb</string>
|
||||
<string name="snygg__rule_element__emoji_key_popup">Emodzsi felugró gomb</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Emodzsi fül</string>
|
||||
<string name="snygg__rule_element__emoji_key_tab">Emodzsi lap</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_layout">Fekvő bemenetelrendezés</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Fekvő bemenet mező</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Fekvő bemenet művelet</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_field">Fekvő bemeneti mező</string>
|
||||
<string name="snygg__rule_element__extracted_landscape_input_action">Fekvő bemeneti művelet</string>
|
||||
<string name="snygg__rule_element__glide_trail">Csúsztatási nyomvonal</string>
|
||||
<string name="snygg__rule_element__incognito_mode_indicator">Inkognitó mód jelző</string>
|
||||
<string name="snygg__rule_element__incognito_mode_indicator">Inkognitó mód jelzője</string>
|
||||
<string name="snygg__rule_element__one_handed_panel">Egykezes panel</string>
|
||||
<string name="snygg__rule_element__smartbar">Okossáv</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_row">Okossáv megosztott műveletek sora</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_toggle">Okossáv megosztott műveletek váltó</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_row">Okossáv bővített műveletek sora</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_toggle">Okossáv bővített műveletek váltó</string>
|
||||
<string name="snygg__rule_element__smartbar_action_key">Okossáv művelet gomb</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_row">Okossáv megosztott műveleteinek sora</string>
|
||||
<string name="snygg__rule_element__smartbar_shared_actions_toggle">Okossáv megosztott műveletei be/ki</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_row">Okossáv bővített műveleteinek sora</string>
|
||||
<string name="snygg__rule_element__smartbar_extended_actions_toggle">Okossáv bővített műveletei be/ki</string>
|
||||
<string name="snygg__rule_element__smartbar_action_key">Okossáv műveletgombja</string>
|
||||
<string name="snygg__rule_element__smartbar_action_tile">Okossáv művelet csempe</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_overflow">Okossáv művelet túlfolyó</string>
|
||||
<string name="snygg__rule_element__smartbar_actions_overflow_customize_button">Okossáv túlfolyó műveleteinek testreszabó gombja</string>
|
||||
@@ -206,7 +203,7 @@
|
||||
<string name="snygg__rule_element__smartbar_candidate_word">Okossáv javaslat szó</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_clip">Okossáv javaslat vágólapról</string>
|
||||
<string name="snygg__rule_element__smartbar_candidate_spacer">Okossáv javaslat elválasztó</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Rendszer navigációs sáv</string>
|
||||
<string name="snygg__rule_element__system_nav_bar">Rendszer navigációs sávja</string>
|
||||
<string name="snygg__rule_selector__pressed">Lenyomott</string>
|
||||
<string name="snygg__rule_selector__focus">Fókuszált</string>
|
||||
<string name="snygg__rule_selector__disabled">Letiltott</string>
|
||||
@@ -214,14 +211,14 @@
|
||||
<string name="snygg__property_name__height">Magasság</string>
|
||||
<string name="snygg__property_name__background">Háttér</string>
|
||||
<string name="snygg__property_name__foreground">Előtér</string>
|
||||
<string name="snygg__property_name__border_color">Szegély szín</string>
|
||||
<string name="snygg__property_name__border_style">Szegély stílus</string>
|
||||
<string name="snygg__property_name__border_width">Szegély szélessége</string>
|
||||
<string name="snygg__property_name__border_color">Szegélyszín</string>
|
||||
<string name="snygg__property_name__border_style">Szegélystílus</string>
|
||||
<string name="snygg__property_name__border_width">Szegélyszélesség</string>
|
||||
<string name="snygg__property_name__font_family">Betűkészlet</string>
|
||||
<string name="snygg__property_name__font_size">Betűméret</string>
|
||||
<string name="snygg__property_name__font_style">Betűstílus</string>
|
||||
<string name="snygg__property_name__font_variant">Betű változat</string>
|
||||
<string name="snygg__property_name__font_weight">Betű vastagság</string>
|
||||
<string name="snygg__property_name__font_variant">Betűváltozat</string>
|
||||
<string name="snygg__property_name__font_weight">Betűvastagság</string>
|
||||
<string name="snygg__property_name__shadow_elevation">Árnyék kiemelés</string>
|
||||
<string name="snygg__property_name__shape">Forma</string>
|
||||
<string name="snygg__property_name__var_primary">Elsődleges szín</string>
|
||||
@@ -392,22 +389,22 @@
|
||||
<string name="pref__glide__immediate_backspace_deletes_word__summary">A csúsztatás után egyből megnyomott törlés gomb az egész szót törli</string>
|
||||
<string name="pref__gestures__general_title" comment="Preference group title">Általános gesztusok</string>
|
||||
<string name="pref__gestures__space_bar_title" comment="Preference group title">Szóköz gesztusok</string>
|
||||
<string name="pref__gestures__other_title" comment="Preference group title">Egyéb gesztusok / gesztusküszöb</string>
|
||||
<string name="pref__gestures__other_title" comment="Preference group title">Egyéb gesztusok / gesztusküszöbök</string>
|
||||
<string name="pref__gestures__swipe_up__label" comment="Preference title">Felhúzás</string>
|
||||
<string name="pref__gestures__swipe_down__label" comment="Preference title">Lehúzás</string>
|
||||
<string name="pref__gestures__swipe_left__label" comment="Preference title">Balra húzás</string>
|
||||
<string name="pref__gestures__swipe_right__label" comment="Preference title">Jobbra húzás</string>
|
||||
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Szóköz felhúzás</string>
|
||||
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Szóköz balra húzás</string>
|
||||
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Szóköz jobbra húzás</string>
|
||||
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Szóköz felhúzása</string>
|
||||
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Szóköz balra húzása</string>
|
||||
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Szóköz jobbra húzása</string>
|
||||
<string name="pref__gestures__space_bar_long_press__label" comment="Preference title">Szóköz hosszú lenyomása</string>
|
||||
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Törlés gomb balra húzás</string>
|
||||
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Törlés gomb balra húzása</string>
|
||||
<string name="pref__gestures__delete_key_long_press__label" comment="Preference title">Törlés gomb hosszan nyomása</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Húzás sebesség küszöb</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Húzás távolság küszöb</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Húzási sebesség küszöbe</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Húzási távolság küszöbe</string>
|
||||
<string name="settings__advanced__title" comment="Title of Advanced settings">Speciális</string>
|
||||
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Beállítások témája</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Rendszer alapértelmezett (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__auto_amoled" comment="Possible value of Settings theme preference in Advanced">Rendszer alapértelmezése (AMOLED)</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Világos</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Sötét</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED sötét</string>
|
||||
@@ -430,11 +427,11 @@
|
||||
<string name="about__changelog__summary" comment="Preference summary">Újdonságok</string>
|
||||
<string name="about__repository__title" comment="Preference title">Kódtár (GitHub)</string>
|
||||
<string name="about__repository__summary" comment="Preference summary">Forráskód, megbeszélések, hibák és információ</string>
|
||||
<string name="about__privacy_policy__title" comment="Preference title">Adatvédelmi Irányelvek</string>
|
||||
<string name="about__privacy_policy__title" comment="Preference title">Adatvédelmi irányelvek</string>
|
||||
<string name="about__privacy_policy__summary" comment="Preference summary">A projekt adatvédelmi irányelvei</string>
|
||||
<string name="about__project_license__title" comment="Preference title">Projekt licenc</string>
|
||||
<string name="about__project_license__summary" comment="Preference summary">A FlorisBoard ez alatt van licencelve: {license_name}</string>
|
||||
<string name="about__project_license__error_license_text_failed" comment="Error text for license text loading failure">Hiba: Hiba a licenc szöveg betöltéskor.\n-> Ok: {error_message}</string>
|
||||
<string name="about__project_license__title" comment="Preference title">Projekt licence</string>
|
||||
<string name="about__project_license__summary" comment="Preference summary">A FlorisBoard {license_name} licenc alatt érhető el</string>
|
||||
<string name="about__project_license__error_license_text_failed" comment="Error text for license text loading failure">Hiba: A licenc szövegének betöltése sikertelen.\n-> Ok: {error_message}</string>
|
||||
<string name="about__project_license__error_reason_asset_manager_null" comment="Error text if asset manager is null">Az elemkezelő hivatkozás üres</string>
|
||||
<string name="about__third_party_licenses__title" comment="Preference title">Harmadik felek licencei</string>
|
||||
<string name="about__third_party_licenses__summary" comment="Preference summary">Az alkalmazásban szereplő harmadik felektől származó könyvtárak licencei</string>
|
||||
@@ -451,9 +448,9 @@
|
||||
<string name="setup__select_ime__switch_keyboard_btn">Billentyűzet váltása</string>
|
||||
<string name="setup__grant_notification_permission__title">Összeomlási jelentések értesítéseinek engedélyezése</string>
|
||||
<string name="setup__grant_notification_permission__description">Az Android 13+ rendszertől kezdve az alkalmazásoknak engedélyt kell kérniük az
|
||||
értesítések küldéséhez.
|
||||
A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon az összeomlási jelentés képernyője.
|
||||
Ez az engedély bármikor megváltoztatható a rendszerbeállításokban.
|
||||
értesítések küldéséhez. A Florisboardban ez csak arra szolgál, hogy
|
||||
összeomlás esetén az összeomlási jelentés képernyője. Ez az engedély
|
||||
bármikor megváltoztatható a rendszerbeállításokban.
|
||||
</string>
|
||||
<string name="setup__grant_notification_permission__btn">Engedély megadása</string>
|
||||
<string name="setup__finish_up__title">Befejezés</string>
|
||||
@@ -461,7 +458,7 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="setup__finish_up__description_p2">Ha bármilyen hibával vagy összeomlással találkozik, vagy csak javaslatot szeretne tenni, nézze meg a projekt kódtárját a névjegy képernyőn!</string>
|
||||
<string name="setup__finish_up__finish_btn">Személyre szabás megkezdése</string>
|
||||
<!-- Back up & Restore -->
|
||||
<string name="backup_and_restore__title">Mentés és visszaállítás</string>
|
||||
<string name="backup_and_restore__title">Mentés és helyreállítás</string>
|
||||
<string name="backup_and_restore__back_up__title">Adatok biztonsági mentése</string>
|
||||
<string name="backup_and_restore__back_up__summary">Biztonsági mentés arcívum generálása a beállításokból és a személyre szabásokból</string>
|
||||
<string name="backup_and_restore__back_up__destination">Biztonsági mentés céljának kiválasztása</string>
|
||||
@@ -469,24 +466,24 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="backup_and_restore__back_up__destination_share_intent">Más alkalmazás a megosztás menün keresztül</string>
|
||||
<string name="backup_and_restore__back_up__files">Válassza ki, hogy miről készít biztonsági mentést</string>
|
||||
<string name="backup_and_restore__back_up__files_jetpref_datastore">Beállítások</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_keyboard">Billentyűzet kiterjesztések</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_keyboard">Billentyűzetkiterjesztések</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_spelling">Helyesírási kiterjesztések / szótárak</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_theme">Téma kiterjesztések</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_theme">Témakiterjesztések</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history">Vágólapelőzmények</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_text_items">Szövegelemek</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_image_items">Képek</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_video_items">Videók</string>
|
||||
<string name="backup_and_restore__back_up__success">Biztonsági mentés archívum sikeresen exportálva!</string>
|
||||
<string name="backup_and_restore__back_up__failure">Nem sikerült exportálni a biztonsági mentés archívumot: {error_message}</string>
|
||||
<string name="backup_and_restore__restore__title">Adatok visszaállítása</string>
|
||||
<string name="backup_and_restore__restore__summary">Beállítások és személyre szabások visszatöltése mentett archívumból</string>
|
||||
<string name="backup_and_restore__restore__files">Válassza ki, hogy mit szeretne visszaállítani</string>
|
||||
<string name="backup_and_restore__restore__metadata">Kiválasztott biztonsági mentés archívum</string>
|
||||
<string name="backup_and_restore__back_up__success">Biztonsági mentési archívum sikeresen exportálva!</string>
|
||||
<string name="backup_and_restore__back_up__failure">Nem sikerült exportálni a biztonsági mentési archívumot: {error_message}</string>
|
||||
<string name="backup_and_restore__restore__title">Adatok helyreállítása</string>
|
||||
<string name="backup_and_restore__restore__summary">Beállítások és testreszabások visszaállítása mentett archívumból</string>
|
||||
<string name="backup_and_restore__restore__files">Válassza ki, hogy mit szeretne helyreállítani</string>
|
||||
<string name="backup_and_restore__restore__metadata">Kiválasztott biztonsági mentési archívum</string>
|
||||
<string name="backup_and_restore__restore__metadata_warn_different_version">Ez az archívum egy korábbi verzióból került mentésre, amely általában támogatott. Azonban felmerülhetnek problémák, vagy egyes beállítások nem feltétlenül töltődnek vissza az eltérő funkciók miatt.</string>
|
||||
<string name="backup_and_restore__restore__metadata_warn_different_vendor">Az archívum egy harmadik fél által kibocsátott alkalmazással készült, amely általában támogatott. Felmerülhet adatvesztés, ezért csak saját felelősségre ajánlott!</string>
|
||||
<string name="backup_and_restore__restore__metadata_error_invalid_metadata">Ez az archívum nem megfelelő metaadatot tartalmaz. Vagy megsérült, vagy módosításra került. Nem lehetséges a betöltés, kérjük válasszon egy másikat.</string>
|
||||
<string name="backup_and_restore__restore__metadata_error_nothing_to_restore">Ez az archívum nem tartalmaz visszatölthető adatot, kérjük válasszon másikat.</string>
|
||||
<string name="backup_and_restore__restore__mode">Visszaállítási mód</string>
|
||||
<string name="backup_and_restore__restore__metadata_warn_different_vendor">Az archívum egy harmadik féltől származó alkalmazással készült, amely általában nem támogatott. Adatvesztés történhet, ezért csak a saját felelősségére állítsa helyre.</string>
|
||||
<string name="backup_and_restore__restore__metadata_error_invalid_metadata">Ez az archívum nem megfelelő metaadatokat tartalmaz. Megsérült, vagy hibásan lett módosítva. Az archívumból való helyreállítás nem lehetséges, válasszon egy másikat.</string>
|
||||
<string name="backup_and_restore__restore__metadata_error_nothing_to_restore">Ez az archívum nem tartalmaz helyreállítható adatokat, válasszon másikat.</string>
|
||||
<string name="backup_and_restore__restore__mode">Helyreállítási mód</string>
|
||||
<string name="backup_and_restore__restore__mode_merge">Egyesítés a jelenlegi adatokkal</string>
|
||||
<string name="backup_and_restore__restore__mode_erase_and_overwrite">Törlés és a jelenlegi adatok felülírása</string>
|
||||
<string name="backup_and_restore__restore__success">Sikeresen visszaállított adatok!</string>
|
||||
@@ -511,14 +508,14 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="clipboard__disabled__message">A {app_name} vágólapelőzményei lehetővé teszik, gyorsan eltároljon és elérjen szövegeket és képeket másolásra, az elemek kitűzésének, az automatikus törlésnek és a maximum elemszám beállításának lehetőségével.</string>
|
||||
<string name="clipboard__disabled__enable_button">Vágólapelőzmények engedélyezése</string>
|
||||
<string name="clipboard__empty__title">A vágólapja üres</string>
|
||||
<string name="clipboard__empty__message">Ha kimásol szövegeket vagy képeket, itt fognak megjelenni.</string>
|
||||
<string name="clipboard__empty__message">Ha szövegeket vagy képeket másol, itt fognak megjelenni.</string>
|
||||
<string name="clipboard__locked__title">A vágólapja zárolva van</string>
|
||||
<string name="clipboard__locked__message">A vágólapelőzmények eléréséhez, kérjük először oldja fel a készülékét.</string>
|
||||
<string name="clipboard__locked__message">A vágólapelőzmények eléréséhez először oldja fel az eszközt.</string>
|
||||
<string name="clipboard__group_pinned">Kitűzött</string>
|
||||
<string name="clipboard__group_recent">Legutóbbi</string>
|
||||
<string name="clipboard__group_other">Egyéb</string>
|
||||
<string name="clipboard__item_description_email">Email</string>
|
||||
<string name="clipboard__item_description_url">URL</string>
|
||||
<string name="clipboard__item_description_email">E-mail-cím</string>
|
||||
<string name="clipboard__item_description_url">Webcím</string>
|
||||
<string name="clipboard__item_description_phone">Telefon</string>
|
||||
<string name="clip__clear_history">Előzmények törlése</string>
|
||||
<string name="clip__unpin_item">Elem levétele</string>
|
||||
@@ -568,8 +565,8 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="devtools__show_key_touch_boundaries__summary" comment="Summary of Show key touch boundaries in Devtools">A billentyűérintési határok körvonalának vörös kiemelése</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">A húzd és vidd segítség megjelenítése</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__summary" comment="Summary of Show drag and drop helpers in Devtools">Debug célból az amúgy láthatatlan segítség megjelenítése a húzd is vidd ablakoknál</string>
|
||||
<string name="devtools__clear_udm_internal_database__label" comment="Label of Clear internal user dictionary database in Devtools">Belső felhasználói szótár adatbázis ürítése</string>
|
||||
<string name="devtools__clear_udm_internal_database__summary" comment="Summary of Clear internal user dictionary database in Devtools">Kiürít minden szót a szótár adatbázis táblázatból</string>
|
||||
<string name="devtools__clear_udm_internal_database__label" comment="Label of Clear internal user dictionary database in Devtools">Belső felhasználói szótáradatbázis ürítése</string>
|
||||
<string name="devtools__clear_udm_internal_database__summary" comment="Summary of Clear internal user dictionary database in Devtools">Kiürít minden szót a szótár adatbázistáblájából</string>
|
||||
<string name="devtools__reset_flag__label" comment="Label of Reset flag preferences in Devtools">{flag_name} zászló visszaállítása</string>
|
||||
<string name="devtools__reset_flag_is_ime_set_up__summary" comment="Summary of Reset is IME set up flag in Devtools">Hibakeresési művelet a beállítás varázsló újbóli megjelenítéséhez</string>
|
||||
<string name="devtools__test_crash_report__label" comment="Label of Test Crash Report in Devtools">Összeomlásjelentő képernyő tesztelése</string>
|
||||
@@ -577,13 +574,18 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="devtools__group_android__title" comment="Title of Android group in Devtools">Android rendszereszközök</string>
|
||||
<string name="devtools__android_settings_global__title" comment="Title of Android settings (global) screen">Globális Android beállítások</string>
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Biztonságos Android beállítások</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Rendszer Android beállítások</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Rendszer nyelvek</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Rendszer Android beállításai</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Rendszer nyelvei</string>
|
||||
<string name="devtools__debuglog__title">Hibakeresési napló</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">A hibakeresési napló a vágólapra lett másolva</string>
|
||||
<string name="devtools__debuglog__copy_log">Napló másolása</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Napló másolása (GitHub formázás)</string>
|
||||
<string name="devtools__debuglog__loading">Betöltés…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Kiegészítők</string>
|
||||
<string name="ext__list__ext_theme">Téma kiterjesztések</string>
|
||||
<string name="ext__list__ext_keyboard">Billentyűzet kiterjesztések</string>
|
||||
<string name="ext__list__ext_languagepack">Nyelvi csomag kiterjesztések</string>
|
||||
<string name="ext__home__title">Kiterjesztések</string>
|
||||
<string name="ext__list__ext_theme">Témakiterjesztések</string>
|
||||
<string name="ext__list__ext_keyboard">Billentyűzetkiterjesztések</string>
|
||||
<string name="ext__list__ext_languagepack">Nyelvicsomag-kiterjesztések</string>
|
||||
<string name="ext__meta__authors">Szerzők</string>
|
||||
<string name="ext__meta__components">Csomagolt összetevők</string>
|
||||
<string name="ext__meta__components_theme">Tartalmazott témák</string>
|
||||
@@ -636,31 +638,31 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="ext__import__file_skip_ext_not_supported" comment="Reason string when file is loaded in incorrect context">Egy médiafájlt várt (kép, hang, betűtípus, stb.), de egy kiterjesztésarchívumot kapott.</string>
|
||||
<string name="ext__import__file_skip_media_not_supported" comment="Reason string when file is loaded in incorrect context">Egy kiterjesztésarchívumot várt, de egy médiafájlt (kép, hang, betűtípus, stb.) kapott.</string>
|
||||
<string name="ext__import__error_unexpected_exception" comment="Label when an error occurred during import. The error message will be appended below this text view">Váratlan hiba történt az importálás során. A részletek a következőek:</string>
|
||||
<string name="ext__validation__enter_package_name">Kérjük adjon meg egy csomagnevet</string>
|
||||
<string name="ext__validation__enter_package_name">Adjon meg egy csomagnevet</string>
|
||||
<string name="ext__validation__error_package_name">A csomagnév nem egyezik a reguláris kifejezéssel: {id_regex}</string>
|
||||
<string name="ext__validation__enter_version">Kérjük adjon meg egy verziót</string>
|
||||
<string name="ext__validation__enter_title">Kérjük adjon meg egy címet</string>
|
||||
<string name="ext__validation__enter_maintainer">Kérjük adjon meg legalább egy érvényes karbantartót</string>
|
||||
<string name="ext__validation__enter_license">Kérjük adjon meg egy licencazonosítót</string>
|
||||
<string name="ext__validation__enter_component_id">Kérjük adjon meg egy összetevőazonosítót</string>
|
||||
<string name="ext__validation__error_component_id">Kérjük adjon meg egy összetevőazonosítót a következőhöz: {component_id_regex}</string>
|
||||
<string name="ext__validation__enter_component_label">Kérjük adjon meg egy összetevőcímet</string>
|
||||
<string name="ext__validation__hint_component_label_to_long">Az összetevőcím elég hosszú, ami lehet, hogy le lesz vágva a felületen</string>
|
||||
<string name="ext__validation__error_author">Kérjük adjon meg legalább egy érvényes szerzőt</string>
|
||||
<string name="ext__validation__enter_version">Adjon meg egy verziót</string>
|
||||
<string name="ext__validation__enter_title">Adjon meg egy címet</string>
|
||||
<string name="ext__validation__enter_maintainer">Adjon meg legalább egy érvényes karbantartót</string>
|
||||
<string name="ext__validation__enter_license">Adjon meg egy licencazonosítót</string>
|
||||
<string name="ext__validation__enter_component_id">Adjon meg egy összetevő-azonosítót</string>
|
||||
<string name="ext__validation__error_component_id">Adjon meg egy összetevő-azonosítót a következőhöz: {component_id_regex}</string>
|
||||
<string name="ext__validation__enter_component_label">Adjon meg egy összetevőcímet</string>
|
||||
<string name="ext__validation__hint_component_label_to_long">Az összetevőcím elég hosszú, lehet, hogy le lesz vágva a felületen</string>
|
||||
<string name="ext__validation__error_author">Adjon meg legalább egy érvényes szerzőt</string>
|
||||
<string name="ext__validation__error_stylesheet_path_blank">A stíluslap útvonala nem lehet üres</string>
|
||||
<string name="ext__validation__error_stylesheet_path">Kérjük adjon meg egy érvényes stíluslap útvonalat a következőhöz: {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Kérjük adjon meg egy változónevet</string>
|
||||
<string name="ext__validation__error_property">Kérjük adjon meg egy változónevet a következőhöz: {variable_name_regex}</string>
|
||||
<string name="ext__validation__error_stylesheet_path">Adjon meg egy érvényes stíluslap-útvonalat a következőhöz: {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Adjon meg egy változónevet</string>
|
||||
<string name="ext__validation__error_property">Adjon meg egy változónevet a következőhöz: {variable_name_regex}</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">Megállapodás szerint a FlorisCSS változónevek két kötőjellel kezdődnek (--)</string>
|
||||
<string name="ext__validation__enter_color">Kérjük adjon meg egy szín sztringet</string>
|
||||
<string name="ext__validation__error_color">Kérjük adjon meg egy érvényes szín sztringet</string>
|
||||
<string name="ext__validation__enter_dp_size">Kérjük adjon meg egy dp méretet</string>
|
||||
<string name="ext__validation__enter_valid_number">Kérjük adjon meg egy érvényes számot</string>
|
||||
<string name="ext__validation__enter_positive_number">Kérjük adjon meg egy pozitív számot (>=0)</string>
|
||||
<string name="ext__validation__enter_percent_size">Kérjük adjon meg egy százalékot</string>
|
||||
<string name="ext__validation__enter_number_between_0_100">Kérjük adjon meg egy pozitív számot 0 és 100 között</string>
|
||||
<string name="ext__validation__hint_value_above_50_percent">Bármilyen érték 50% felett úgy fog viselkedni, mintha 50%-ra állította volna, fontolja meg hogy csökkenti a százalékot</string>
|
||||
<string name="ext__update_box__internet_permission_hint">Mivel ennek az alkalmazásnak nincs internetelérési útvonala, a telepített kiterjesztések frissítéseit manuálisan kell engedélyezni.</string>
|
||||
<string name="ext__validation__enter_color">Adjon meg egy színkarakterláncot</string>
|
||||
<string name="ext__validation__error_color">Adjon meg egy érvényes színkarakterláncot</string>
|
||||
<string name="ext__validation__enter_dp_size">Adjon meg egy dp méretet</string>
|
||||
<string name="ext__validation__enter_valid_number">Adjon meg egy érvényes számot</string>
|
||||
<string name="ext__validation__enter_positive_number">Adjon meg egy pozitív számot (>=0)</string>
|
||||
<string name="ext__validation__enter_percent_size">Adjon meg egy százalékot</string>
|
||||
<string name="ext__validation__enter_number_between_0_100">Adjon meg egy pozitív számot 0 és 100 között</string>
|
||||
<string name="ext__validation__hint_value_above_50_percent">Bármilyen 50% feletti érték úgy fog viselkedni, mintha 50%-ra állította volna, fontolja meg hogy csökkenti a százalékot</string>
|
||||
<string name="ext__update_box__internet_permission_hint">Mivel ennek az alkalmazásnak nincs internetelérési engedélye, a telepített kiterjesztések frissítéseit kézileg kell ellenőrizni.</string>
|
||||
<string name="ext__update_box__search_for_updates">Frissítések keresése</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">{extensions} kezelése</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">A kiterjesztések importálásával, exportálásával, létrehozásával, testreszabásával és eltávolításával kapcsolatos összes feladat a központi kiterjesztéskezelőn keresztül kezelhető.</string>
|
||||
@@ -669,6 +671,7 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="ext__home__visit_store">Kiegészítőbolt meglátogatása</string>
|
||||
<string name="ext__home__manage_extensions">Telepített kiterjesztések kezelése</string>
|
||||
<string name="ext__list__view_details">Részletek megtekintése</string>
|
||||
<string name="ext__check_updates__title">Frissítések keresése</string>
|
||||
<!-- Action strings -->
|
||||
<string name="action__add">Hozzáadás</string>
|
||||
<string name="action__apply">Alkalmaz</string>
|
||||
@@ -687,7 +690,7 @@ A Florisboard-ban ez csak arra szolgál, hogy összeomlás esetén megnyíljon a
|
||||
<string name="action__import">Importálás</string>
|
||||
<string name="action__no">Nem</string>
|
||||
<string name="action__ok">OK</string>
|
||||
<string name="action__restore">Visszaállítás</string>
|
||||
<string name="action__restore">Helyreállítás</string>
|
||||
<string name="action__save">Mentés</string>
|
||||
<string name="action__select">Kiválasztás</string>
|
||||
<string name="action__select_dir">Könyvtár kiválasztása</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emoji</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emotikon</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Ukuran maksimum histori emoji</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Warna kulit emoji yang disukai</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Gaya rambut emoji yang disukai</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,9 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Objek</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Simbol</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Bendera</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Tidak ditemukan emoji yang digunakan baru-baru ini. Setelah Anda mulai mengetikkan emoji, mereka akan muncul di sini secara otomatis.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro tip: Tekan lama emoji yang terakhir digunakan untuk menghapusnya dari tampilan ini!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Menghapus {emoji} dari emoji terakhir yang digunakan</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Panah atas</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Lakukan panah atas</string>
|
||||
@@ -308,6 +304,7 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Tundaan tekan lama tombol</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Bilah spasi beralih ke karakter</string>
|
||||
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Beralih kembali ke karakter saat dalam simbol atau numerik secara otomatis</string>
|
||||
<string name="pref__keyboard__incognito_indicator__label" comment="Preference title">Indikator samaran</string>
|
||||
<!-- Smartbar strings -->
|
||||
<string name="settings__smartbar__title" comment="Title of Smartbar screen">Smartbar</string>
|
||||
<string name="pref__smartbar__enabled__label" comment="Preference title">Aktifkan Smartbar</string>
|
||||
@@ -410,6 +407,7 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Cerah</string>
|
||||
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Gelap</string>
|
||||
<string name="pref__advanced__settings_theme__amoled_dark" comment="Possible value of Settings theme preference in Advanced">AMOLED Gelap</string>
|
||||
<string name="pref__advanced__settings_material_you__label" comment="Label of Material You preference in Advanced">Gunakan Material You</string>
|
||||
<string name="pref__advanced__settings_language__label" comment="Label of Settings language preference in Advanced">Bahasa pengaturan</string>
|
||||
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Tampilkan ikon aplikasi pada peluncur</string>
|
||||
<string name="pref__advanced__show_app_icon__summary_atleast_q" comment="Summary of Show app icon preference in Advanced for Android 10+">Selalu diaktifkan di Android 10+ karena pembatasan sistem</string>
|
||||
@@ -447,6 +445,12 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="setup__select_ime__title">Pilih {app_name}</string>
|
||||
<string name="setup__select_ime__description">{app_name} sekarang sudah diaktifkan di sistem Anda. Untuk menggunakannya secara aktif, beralihlah ke {app_name} dengan memilihnya di dialog pemilih input!</string>
|
||||
<string name="setup__select_ime__switch_keyboard_btn">Ubah Papan Ketik</string>
|
||||
<string name="setup__grant_notification_permission__title">Izinkan Notifikasi Pelaporan Crash</string>
|
||||
<string name="setup__grant_notification_permission__description">Per-Android 13+, apl harus meminta izin untuk
|
||||
mengirim notifikasi. Pada Florisboard, izin tersebut hanya digunakan untuk membuka jendela pelaporan crash pada saat terjadi crash.
|
||||
Izin ini dapat diubah kapanpun pada setelan sistem.
|
||||
</string>
|
||||
<string name="setup__grant_notification_permission__btn">Izinkan</string>
|
||||
<string name="setup__finish_up__title">Selesaikan</string>
|
||||
<string name="setup__finish_up__description_p1">{app_name} sekarang sudah diaktifkan di sistem ini dan siap untuk disesuaikan oleh Anda.</string>
|
||||
<string name="setup__finish_up__description_p2">Jika Anda mengalami masalah, bug, crash, atau hanya ingin membuat saran, lihat repositori proyek di layar tentang!</string>
|
||||
@@ -463,6 +467,10 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_keyboard">Ekstensi papan ketik</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_spelling">Ekstensi / kamus ejaan</string>
|
||||
<string name="backup_and_restore__back_up__files_ime_theme">Ekstensi tema</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history">Histori papan klip</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_text_items">Item teks</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_image_items">Gambar</string>
|
||||
<string name="backup_and_restore__back_up__files_clipboard_history__clipboard_video_items">Video</string>
|
||||
<string name="backup_and_restore__back_up__success">Berhasil mengekspor arsip cadangan!</string>
|
||||
<string name="backup_and_restore__back_up__failure">Gagal untuk mengekspor arsip cadangan: {error_message}</string>
|
||||
<string name="backup_and_restore__restore__title">Pulihkan data</string>
|
||||
@@ -534,6 +542,11 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="pref__clipboard__max_history_size__label">Batas ukuran riwayat</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__label">Membersihkan klip utama memengaruhi riwayat</string>
|
||||
<string name="pref__clipboard__clear_primary_clip_deletes_last_item__summary">Membersihkan klip utama juga menghapus entri riwayat terkini</string>
|
||||
<string name="send_to_clipboard__unknown_error">Terjadi kesalahan yang tidak diketahui. Harap coba lagi!</string>
|
||||
<string name="send_to_clipboard__type_not_supported_error">Jenis media ini tidak didukung.</string>
|
||||
<string name="send_to_clipboard__android_version_to_old_error">Versi android terlalu lawas untuk fitur ini.
|
||||
</string>
|
||||
<string name="send_to_clipboard__description__copied_image_to_clipboard">Salin gambar berikut ke papan klip.</string>
|
||||
<!-- Devtools strings -->
|
||||
<string name="devtools__title" comment="Title of Devtools screen. Translators: treat this string as 'Developer tools' for translation, except a similar short term is available for your language.">Alat pengembang</string>
|
||||
<string name="devtools__enabled__label" comment="Label of Enable developer tools in Devtools">Aktifkan alat pengembang</string>
|
||||
@@ -562,6 +575,10 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Pengaturan sistem Android</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Sistem lokal</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Addon & Ekstensi</string>
|
||||
<string name="ext__list__ext_theme">Ekstensi tema</string>
|
||||
<string name="ext__list__ext_keyboard">Ekstensi keyboard</string>
|
||||
<string name="ext__list__ext_languagepack">Ekstensi paket bahasa</string>
|
||||
<string name="ext__meta__authors">Pembuat</string>
|
||||
<string name="ext__meta__components">Komponen yang dibundel</string>
|
||||
<string name="ext__meta__components_theme">Tema terbundel</string>
|
||||
@@ -614,6 +631,40 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="ext__import__file_skip_ext_not_supported" comment="Reason string when file is loaded in incorrect context">Diduga sebuah file media (gambar, suara, font, dll.) tetapi menemukan sebuah arsip ekstensi.</string>
|
||||
<string name="ext__import__file_skip_media_not_supported" comment="Reason string when file is loaded in incorrect context">Diduga sebuah arsip ekstensi tetapi menemukan sebuah file media (gambar, suara, font, dll.).</string>
|
||||
<string name="ext__import__error_unexpected_exception" comment="Label when an error occurred during import. The error message will be appended below this text view">Sebuah kesalahan yang tidak terduga terjadi saat mengimpor. Detail berikut ini disediakan:</string>
|
||||
<string name="ext__validation__enter_package_name">Harap masukkan nama paket</string>
|
||||
<string name="ext__validation__error_package_name">Nama paket tidak cocok dengan regex {id_regex}</string>
|
||||
<string name="ext__validation__enter_version">Harap masukkan versi</string>
|
||||
<string name="ext__validation__enter_title">Harap masukkan judul</string>
|
||||
<string name="ext__validation__enter_maintainer">Harap masukkan setidaknya seorang maintener yang valid</string>
|
||||
<string name="ext__validation__enter_license">Harap masukkan lisensi pengidentifikasi</string>
|
||||
<string name="ext__validation__enter_component_id">Harap masukkan ID komponen</string>
|
||||
<string name="ext__validation__error_component_id">Harap masukkan ID komponen yang cocok dengan {component_id_regex}</string>
|
||||
<string name="ext__validation__enter_component_label">Harap masukkan label komponen</string>
|
||||
<string name="ext__validation__hint_component_label_to_long">Label komponen Anda terlalu panjang, yang mungkin akan terlipat pada jendela UI</string>
|
||||
<string name="ext__validation__error_author">Harap masukkan setidaknya seorang pembuat yang valid</string>
|
||||
<string name="ext__validation__error_stylesheet_path_blank">Alur stylesheet tidak boleh kosong</string>
|
||||
<string name="ext__validation__error_stylesheet_path">Harap masukkan alur stylesheet yang valid cocok dengan {stylesheet_path_regex}</string>
|
||||
<string name="ext__validation__enter_property">Harap masukkan nama variabel</string>
|
||||
<string name="ext__validation__error_property">Harap masukkan nama variabel yang valid cocok dengan {variable_name_regex}</string>
|
||||
<string name="ext__validation__hint_property" tools:ignore="TypographyDashes">Berdasarkan konvensi nama variabel FlorisCSS dimulai dengan dua garis strip (--)</string>
|
||||
<string name="ext__validation__enter_color">Harap masukkan string warna</string>
|
||||
<string name="ext__validation__error_color">Harap masukkan string warna yang valid</string>
|
||||
<string name="ext__validation__enter_dp_size">Harap masukkan ukuran dp</string>
|
||||
<string name="ext__validation__enter_valid_number">Harap masukkan angka yang valid</string>
|
||||
<string name="ext__validation__enter_positive_number">Harap masukkan bilangan positif (>=0)</string>
|
||||
<string name="ext__validation__enter_percent_size">Harap masukkan ukuran persen</string>
|
||||
<string name="ext__validation__enter_number_between_0_100">Harap masukkan bilangan positif antara 0 dan 100</string>
|
||||
<string name="ext__validation__hint_value_above_50_percent">Nilai apa pun di atas 50% akan berperilaku seolah-olah Anda menetapkan 50%, pertimbangkan untuk menurunkan ukuran persen Anda</string>
|
||||
<string name="ext__update_box__internet_permission_hint">Karena aplikasi ini tidak memiliki izin Internet, pembaruan untuk ekstensi yang diinstal harus diperiksa secara manual.</string>
|
||||
<string name="ext__update_box__search_for_updates">Cari Pembaruan</string>
|
||||
<string name="ext__addon_management_box__managing_placeholder">Kelola {extensions}</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">Semua tugas yang terkait dengan mengimpor, mengekspor, membuat, menyesuaikan, dan menghapus ekstensi dapat ditangani melalui manajer addon terpusat.</string>
|
||||
<string name="ext__addon_management_box__go_to_page">Ke {ext_home_title}</string>
|
||||
<string name="ext__home__info">Anda dapat mengunduh dan menginstal ekstensi dari FlorisBoard Addons Store atau mengimpor file ekstensi apa pun yang telah Anda unduh dari internet.</string>
|
||||
<string name="ext__home__visit_store">Kunjungi Add-ons Store</string>
|
||||
<string name="ext__home__manage_extensions">Kelola ekstensi terpasang</string>
|
||||
<string name="ext__list__view_details">Lihat rincian</string>
|
||||
<string name="ext__check_updates__title">Periksa Pembaruan</string>
|
||||
<!-- Action strings -->
|
||||
<string name="action__add">Tambahkan</string>
|
||||
<string name="action__apply">Terapkan</string>
|
||||
@@ -708,6 +759,8 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="enum__key_hint_mode__hint_priority__description" comment="Enum value description">Karakter awal yang dipilih setelah ditekan lama selalu merupakan simbol petunjuk, atau aksen utama jika tidak ada simbol petunjuk yang tersedia</string>
|
||||
<string name="enum__key_hint_mode__smart_priority" comment="Enum value label">Prioritas pintar</string>
|
||||
<string name="enum__key_hint_mode__smart_priority__description" comment="Enum value description">Karakter awal yang dipilih setelah ditekan lama secara dinamis akan memutuskan untuk menjadi aksen utama atau simbol petunjuk, berdasarkan bahasa dan tata letak saat ini</string>
|
||||
<string name="enum__incognito_display_mode__replace_shared_actions_toggle" comment="Enum value label">Ganti ikon sakelar tindakan bersama dengan indikator penyamaran</string>
|
||||
<string name="enum__incognito_display_mode__display_behind_keyboard" comment="Enum value label">Tampilkan indikator penyamaran di belakang keyboard</string>
|
||||
<string name="enum__incognito_mode__force_off" comment="Enum value label">Matikan secara paksa</string>
|
||||
<string name="enum__incognito_mode__force_off__description" comment="Enum value description">Mode samaran akan selalu dinonaktifkan, tidak tergantung pada opsi dari aplikasi. Tindakan cepat samaran dalam Smartbar tidak akan selalu tersedia dengan opsi ini.</string>
|
||||
<string name="enum__incognito_mode__force_on" comment="Enum value label">Nyalakan secara paksa</string>
|
||||
@@ -742,23 +795,23 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="enum__smartbar_layout__suggestions_actions_extended__description" comment="Enum value description">Baris dan baris tindakan yang dapat dialih tambahan statis, dengan tindakan menempel</string>
|
||||
<string name="enum__snygg_level__basic" comment="Enum value label">Dasar</string>
|
||||
<string name="enum__snygg_level__basic__description" comment="Enum value description">Hanya properti warna yang ditampilkan, properti dan aturan diterjemahkan.</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Tingkat lanjut</string>
|
||||
<string name="enum__snygg_level__advanced__description" comment="Enum value description">Semua properti warna yang ditampilkan, properti dan aturan diterjemahkan.</string>
|
||||
<string name="enum__snygg_level__advanced" comment="Enum value label">Lanjutan</string>
|
||||
<string name="enum__snygg_level__advanced__description" comment="Enum value description">Semua properti ditampilkan, properti dan aturan diterjemahkan.</string>
|
||||
<string name="enum__snygg_level__developer" comment="Enum value label">Pengembang</string>
|
||||
<string name="enum__snygg_level__developer__description" comment="Enum value description">Semua properti ditampilkan, properti dan aturan ditampilkan seperti yang tertulis di file lembar gayanya.</string>
|
||||
<string name="enum__snygg_level__developer__description" comment="Enum value description">Semua properti ditampilkan, properti dan aturan ditampilkan seperti yang tertulis pada file stylesheet tersebut.</string>
|
||||
<string name="enum__space_bar_mode__nothing" comment="Enum value label">Tidak ada label</string>
|
||||
<string name="enum__space_bar_mode__current_language" comment="Enum value label">Bahasa saat ini</string>
|
||||
<string name="enum__space_bar_mode__space_bar_key" comment="Enum value label">␣</string>
|
||||
<string name="enum__spelling_language_mode__use_system_languages" comment="Enum value label">Gunakan bahasa sistem</string>
|
||||
<string name="enum__spelling_language_mode__use_keyboard_subtypes" comment="Enum value label">Gunakan subtipe papan ketik</string>
|
||||
<string name="enum__spelling_language_mode__use_keyboard_subtypes" comment="Enum value label">Gunakan subtipe keyboard</string>
|
||||
<string name="enum__swipe_action__no_action" comment="Enum value label">Tidak ada aksi</string>
|
||||
<string name="enum__swipe_action__cycle_to_previous_keyboard_mode" comment="Enum value label">Ubah ke mode papan ketik sebelumnya</string>
|
||||
<string name="enum__swipe_action__cycle_to_next_keyboard_mode" comment="Enum value label">Ubah ke mode papan ketik selanjutnya</string>
|
||||
<string name="enum__swipe_action__cycle_to_previous_keyboard_mode" comment="Enum value label">Ubah ke mode keyboard sebelumnya</string>
|
||||
<string name="enum__swipe_action__cycle_to_next_keyboard_mode" comment="Enum value label">Ubah ke mode keyboard selanjutnya</string>
|
||||
<string name="enum__swipe_action__delete_character" comment="Enum value label">Hapus karakter sebelum kursor</string>
|
||||
<string name="enum__swipe_action__delete_characters_precisely" comment="Enum value label">Hapus karakter secara tepat</string>
|
||||
<string name="enum__swipe_action__delete_word" comment="Enum value label">Hapus kata sebelum kursor</string>
|
||||
<string name="enum__swipe_action__delete_words_precisely" comment="Enum value label">Hapus kata secara tepat</string>
|
||||
<string name="enum__swipe_action__hide_keyboard" comment="Enum value label">Sembunyikan papan ketik</string>
|
||||
<string name="enum__swipe_action__hide_keyboard" comment="Enum value label">Sembunyikan keyboard</string>
|
||||
<string name="enum__swipe_action__insert_space" comment="Enum value label">Masukkan spasi</string>
|
||||
<string name="enum__swipe_action__move_cursor_up" comment="Enum value label">Pindahkan kursor ke atas</string>
|
||||
<string name="enum__swipe_action__move_cursor_down" comment="Enum value label">Pindahkan kursor ke bawah</string>
|
||||
@@ -768,7 +821,7 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="enum__swipe_action__move_cursor_end_of_line" comment="Enum value label">Pindahkan kursor ke akhir baris</string>
|
||||
<string name="enum__swipe_action__move_cursor_start_of_page" comment="Enum value label">Pindahkan kursor ke awal halaman</string>
|
||||
<string name="enum__swipe_action__move_cursor_end_of_page" comment="Enum value label">Pindahkan kursor ke akhir halaman</string>
|
||||
<string name="enum__swipe_action__switch_to_clipboard_context" comment="Enum value label">Buka pengelola/riwayat papan klip</string>
|
||||
<string name="enum__swipe_action__switch_to_clipboard_context" comment="Enum value label">Buka manager/histori papan klip</string>
|
||||
<string name="enum__swipe_action__shift" comment="Enum value label">Shift</string>
|
||||
<string name="enum__swipe_action__redo" comment="Enum value label">Ulangi</string>
|
||||
<string name="enum__swipe_action__undo" comment="Enum value label">Urungkan</string>
|
||||
@@ -779,13 +832,13 @@ Klik di sini untuk menyelesaikan masalah ini.</string>
|
||||
<string name="enum__swipe_action__switch_to_prev_subtype" comment="Enum value label">Beralih ke subtipe sebelumnya</string>
|
||||
<string name="enum__swipe_action__switch_to_next_subtype" comment="Enum value label">Beralih ke subtipe selanjutnya</string>
|
||||
<string name="enum__swipe_action__toggle_smartbar_visibility" comment="Enum value label">Alih visibilitas Smartbar</string>
|
||||
<string name="enum__theme_mode__always_day" comment="Enum value label">Selalu pagi</string>
|
||||
<string name="enum__theme_mode__always_day" comment="Enum value label">Selalu siang</string>
|
||||
<string name="enum__theme_mode__always_night" comment="Enum value label">Selalu malam</string>
|
||||
<string name="enum__theme_mode__follow_system" comment="Enum value label">Ikuti sistem</string>
|
||||
<string name="enum__theme_mode__follow_time" comment="Enum value label">Ikuti waktu</string>
|
||||
<string name="enum__utility_key_action__switch_to_emojis" comment="Enum value label">Beralih ke emoji</string>
|
||||
<string name="enum__utility_key_action__switch_language" comment="Enum value label">Beralih bahasa</string>
|
||||
<string name="enum__utility_key_action__switch_keyboard_app" comment="Enum value label">Beralih aplikasi papan ketik</string>
|
||||
<string name="enum__utility_key_action__switch_keyboard_app" comment="Enum value label">Beralih aplikasi keyboard</string>
|
||||
<string name="enum__utility_key_action__dynamic_switch_language_emojis" comment="Enum value label">Dinamis: Beralih ke emoji / Beralih bahasa</string>
|
||||
<!-- Unit strings (symbols) -->
|
||||
<!-- Unit strings (written words) -->
|
||||
|
||||
@@ -13,9 +13,14 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emoji</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticons</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Dimensione massima della cronologia degli emoji</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Carnagione emoji preferita</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Acconciatura emoji preferita</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">Emoji usate</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">Abilita storico Emoji</string>
|
||||
<string name="prefs__media__emoji_history_enabled__summary" comment="Preference summary">Conserva le emoji usate recentemente per un accesso rapido</string>
|
||||
<string name="prefs__media__emoji_history_pinned_update_strategy" comment="Preference title">Pianifica aggiornamento (selezionato)</string>
|
||||
<string name="prefs__media__emoji_history_recent_update_strategy" comment="Preference title">Pianifica aggiornamento (recente)</string>
|
||||
<string name="prefs__media__emoji_history_max_size">Numero massimo di elementi da tenere</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Faccine & Emoticons</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Persone & Corpo</string>
|
||||
@@ -26,10 +31,12 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Oggetti</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Simboli</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Bandiere</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Non è stata trovata nessuna emoji usata di recente. Una volta che inizi a digitare le emoji appariranno automaticamente qui.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Per accedere alla cronologia delle emoji, sbloccare prima il dispositivo.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Consiglio: premi a lungo le emoji usate di recente per rimuoverle di nuovo da questa vista!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji} rimosso dagli emoji usati di recente</string>
|
||||
<string name="emoji__history__empty_message" comment="Message if the emoji history is empty">Nessuna emoji usata recentemente è stata trovata. Quando inizierai a scrivere appariranno qui.</string>
|
||||
<string name="emoji__history__phone_locked_message" comment="Message to show if phone is locked">Per accedere allo storico emoji, prima sblocca il dispositivo.</string>
|
||||
<string name="emoji__history__usage_tip" comment="Feature discoverability for actions of emoji history">Suggerimento: Tieni premuto a lungo sulle emoji nello storico per selezionarle o rimuoverle!</string>
|
||||
<string name="emoji__history__removal_success_message" comment="Toast message if user has used the delete action on an emoji in the emoji history">{emoji} rimossa dallo storico</string>
|
||||
<string name="emoji__history__pinned">Selezionata</string>
|
||||
<string name="emoji__history__recent">Recente</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Freccia su</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Eseguire freccia su</string>
|
||||
@@ -612,6 +619,7 @@
|
||||
<string name="ext__validation__enter_version">Inserisci una versione</string>
|
||||
<string name="ext__validation__enter_title">Inserisci un titolo</string>
|
||||
<string name="ext__validation__enter_maintainer">Inserisci un indirzzo e-mail valido</string>
|
||||
<string name="ext__validation__enter_license">Inserisci un ID per la licenza</string>
|
||||
<string name="ext__validation__enter_component_id">Inserisci l\'ID corretto</string>
|
||||
<string name="ext__addon_management_box__addon_manager_info">Tutte le attività relative all\'importazione, all\'esportazione, alla creazione, alla personalizzazione e alla rimozione delle estensioni possono essere gestite tramite il gestore interno</string>
|
||||
<string name="ext__home__info">Puoi scaricare e installare estensioni dallo Store di FlorisBoard o importare qualsiasi addon</string>
|
||||
@@ -685,6 +693,14 @@
|
||||
<string name="enum__display_language_names_in__system_locale__description" comment="Enum value description">I nomi delle lingue nell\'app e nell\'interfaccia utente della tastiera vengono visualizzati nella lingua che è impostata per tutto il dispositivo</string>
|
||||
<string name="enum__display_language_names_in__native_locale" comment="Enum value label">Lingua originaria</string>
|
||||
<string name="enum__display_language_names_in__native_locale__description" comment="Enum value description">I nomi delle lingue nell\'app e nell\'interfaccia utente della tastiera vengono visualizzati nella lingua a cui fanno riferimento</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend" comment="Enum value label">Ordinamento automatico (anteponi)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_prepend__description" comment="Enum value description">Ordina automaticamente le emoji in base al loro utilizzo. Le nuove emoji verranno aggiunte all\'inizio.</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append" comment="Enum value label">Ordinamento automatico (aggiungi)</string>
|
||||
<string name="enum__emoji_history_update_strategy__auto_sort_append__description" comment="Enum value description">Ordina automaticamente le emoji in base al loro utilizzo. Le nuove emoji verranno aggiunte alla fine.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend" comment="Enum value label">Ordinamento manuale (anteponi)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_prepend__description" comment="Enum value description">Non ordinare automaticamente le emoji. Le nuove emoji saranno aggiunte all\'inizio.</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append" comment="Enum value label">Ordinamento manuale (aggiungi)</string>
|
||||
<string name="enum__emoji_history_update_strategy__manual_sort_append__description" comment="Enum value description">Non ordinare automaticamente le emoji. Le nuove emoji saranno aggiunte alla fine.</string>
|
||||
<string name="enum__emoji_skin_tone__default" comment="Enum value label">{emoji} Carnagione predefinita</string>
|
||||
<string name="enum__emoji_skin_tone__light_skin_tone" comment="Enum value label">{emoji} Carnagione chiara</string>
|
||||
<string name="enum__emoji_skin_tone__medium_light_skin_tone" comment="Enum value label">{emoji} Carnagione medio-chiara</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">אימוג\'ים</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">סמלי הבעה</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">קמוג\'י</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">היסטוריית האימוג\'י בגודל מקסימלי</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">גוון עור אמוג\'י מועדף</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">סגנון שיער אמוג\'י מועדף</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,10 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">אובייקטים</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">סמלים</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">דגלים</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">לא נמצאו אימוג\'ים שנעשה בהם שימוש לאחרונה. ברגע שתתחיל להקליד אימוג\'ים הם יופיעו כאן באופן אוטומטי.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">כדי לגשת להיסטוריית האמוג׳י שלך, קודם יש לפתוח את נעילת המכשיר.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">טיפ למקצוענים: לחיצה ארוכה השתמשה לאחרונה באימוג\'ים כדי להסיר אותם מתצוגה זו שוב!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">הוסר {emoji} מאמוג\'ים שהיו בשימוש לאחרונה</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">חץ למעלה</string>
|
||||
<string name="quick_action__arrow_up__tooltip">ביצוע חץ למעלה</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">絵文字</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">絵文字</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">顔文字</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">絵文字履歴の最大サイズ</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">好みの絵文字の肌の色</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">好みの絵文字ヘアスタイル</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,13 +25,13 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">オブジェクト</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">シンボル</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">旗</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">最近使用した絵文字は見つかりませんでした。 絵文字を使用すると、絵文字が自動的にここに表示されます</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">ヒント:最近使用した絵文字を長押しして、このビューから再び削除します。</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">最近使用した絵文字から {emoji} を削除しました</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">上矢印</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Perform arrow up</string>
|
||||
<string name="quick_action__arrow_down" maxLength="12">下矢印</string>
|
||||
<string name="quick_action__arrow_down__tooltip">Perform arrow up</string>
|
||||
<string name="quick_action__arrow_left" maxLength="12">左矢印</string>
|
||||
<string name="quick_action__arrow_left__tooltip"></string>
|
||||
<string name="quick_action__arrow_right" maxLength="12">右矢印</string>
|
||||
<string name="quick_action__clipboard_copy" maxLength="12">コピー</string>
|
||||
<string name="quick_action__clipboard_cut" maxLength="12">カット</string>
|
||||
|
||||
@@ -13,9 +13,14 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">이모지</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">이모티콘</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">카오모지</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">이모지 사용 기록 최대 크기</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">선호하는 이모지 피부색</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">선호하는 이모지 머리 스타일</string>
|
||||
<string name="prefs__media__emoji_history__title" comment="Preference group title">이모지 기록</string>
|
||||
<string name="prefs__media__emoji_history_enabled" comment="Preference title">이모지 기록 사용</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">이모지 제안</string>
|
||||
<string name="prefs__media__emoji_suggestion_enabled" comment="Preference title">이모지 제안 사용</string>
|
||||
<string name="prefs__media__emoji_suggestion_update_history" comment="Preference title">이모지 기록 업데이트</string>
|
||||
<string name="prefs__media__emoji_suggestion_candidate_show_name" comment="Preference title">이모지 이름 표시</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">스마일리 및 이모티콘</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">사람 및 신체</string>
|
||||
@@ -26,9 +31,7 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">사물</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">상징</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">깃발</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">최근에 이모지를 사용하지 않았습니다. 이모지를 사용하면 사용한 이모지가 여기에 나타납니다.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">꿀팁: 이모지를 길게 누르면 이 목록에서 이모지를 지울 수 있어요!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">최근에 사용한 이모지에서 {emoji} 이모지를 제거했습니다.</string>
|
||||
<string name="emoji__history__recent">최근</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">화살표 위로</string>
|
||||
<string name="quick_action__arrow_up__tooltip">위쪽 화살표 동작 실행</string>
|
||||
@@ -122,6 +125,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">하나 이상의 필드를 선택하지 않았습니다. 모든 필드의 항목을 선택해 주세요.</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (설치되어 있지 않음)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">레이아웃</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">삭제 확인</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">정말 이 하위 유형을 삭제하시겠습니까?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">테마</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">테마 모드</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">일출 시간</string>
|
||||
@@ -246,20 +251,26 @@
|
||||
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">캡스락 상태 기억</string>
|
||||
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">다른 텍스트 필드로 이동할 때 캡스락 상태 유지</string>
|
||||
<string name="pref__correction__double_space_period__label" comment="Preference title">스페이스 두 번으로 마침표 입력</string>
|
||||
<string name="pref__correction__double_space_period__summary" comment="Preference summary">스페이스 바를 두 번 눌러 마침표를 입력합니다.</string>
|
||||
<string name="pref__correction__double_space_period__summary" comment="Preference summary">스페이스 바를 두 번 눌러 마침표 입력</string>
|
||||
<string name="pref__spelling__title" comment="Preference group title">맞춤법 검사</string>
|
||||
<string name="pref__spelling__active_spellchecker__summary_none">설정한 맞춤법 검사기 서비스가 없습니다. 여기를 눌러 서비스를 설정하세요.</string>
|
||||
<string name="pref__spelling__language_mode__label" comment="Label of Language mode pref">언어</string>
|
||||
<string name="pref__spelling__use_contacts__label" comment="Label of Use contact list pref">연락처 이름 사용</string>
|
||||
<string name="pref__spelling__use_contacts__summary" comment="Summary of Use contact list pref">연락처 목록에서 이름을 찾아 표시합니다.</string>
|
||||
<string name="pref__spelling__use_contacts__summary" comment="Summary of Use contact list pref">연락처 목록에서 이름을 찾아 표시</string>
|
||||
<string name="pref__spelling__use_udm_entries__label" comment="Label of Use user dictionary entries pref">사용자 사전 사용</string>
|
||||
<string name="pref__spelling__use_udm_entries__summary" comment="Summary of Use user dictionary entries pref">사용자 사전에서 항목을 찾아 표시합니다.</string>
|
||||
<string name="pref__spelling__use_udm_entries__summary" comment="Summary of Use user dictionary entries pref">사용자 사전에서 항목을 찾아 표시</string>
|
||||
<string name="settings__dictionary__title" comment="Title of the User dictionaries screen">사용자 사전</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">사용자 사전 사용</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">시스템 사용자 사전에 저장되어 있는 단어를 추천합니다.</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">시스템 사용자 사전 사용</string>
|
||||
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">시스템 사용자 사전에 저장된 단어 추천</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__label" comment="Preference title">시스템 사용자 사전 관리</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">시스템 사용자 사전의 항목을 확인, 추가 또는 제거합니다.</string>
|
||||
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">시스템 사용자 사전 항목 확인, 추가 및 제거</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__label" comment="Preference title">앱 내장 사용자 사전 사용</string>
|
||||
<string name="pref__dictionary__enable_internal_user_dictionary__summary" comment="Preference summary">앱 내장 사용자 사전에 저장된 단어 추천</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__label" comment="Preference title">앱 내장 사용자 사전 관리</string>
|
||||
<string name="pref__dictionary__manage_floris_user_dictionary__summary" comment="Preference summary">앱 내장 사용자 사전 항목 확인, 추가 및 제거</string>
|
||||
<string name="settings__udm__title_floris" comment="Title of the User Dictionary Manager activity for internal">앱 내장 사용자 사전</string>
|
||||
<string name="settings__udm__title_system" comment="Title of the User Dictionary Manager activity for system">시스템 사용자 사전</string>
|
||||
<string name="settings__udm__no_words_in_dictionary" comment="String to show if no words are present in the dictionary">이 사용자 사전에는 저장된 단어가 없습니다.</string>
|
||||
<string name="settings__udm__open_system_manager_ui" comment="Label of the Open system manager UI menu option">시스템 관리자 UI 열기</string>
|
||||
<string name="settings__udm__dictionary_import_success" comment="Message for dictionary import success">사용자 사전을 잘 가져왔습니다!</string>
|
||||
<string name="settings__udm__dictionary_export_success" comment="Message for dictionary export success">사용자 사전을 잘 내보냈습니다!</string>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojîyan</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Hestnîşan</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Mezinahiya dîrokê emûcîyan</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Tona çermê emojî ya tercîhkirî</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Tercîha porê emojî</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,9 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Amanc</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Sembol</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Alayen</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Emojîyên ku di demên dawî da hatine bikarînan nehatine dîtin. Piştî ku te dest bi tîpkirina emojîyan kir, dê li vir bi awayekî otomatîk xuya bibin.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro tip: Çapemeniya dirêj di demên dawî de emojî bikar anîn da ku wan ji vê nêrînê dîsa rakin!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">Rakirin {emoji} ji emojiyên ku di demên dawî de hatine bikaranîn</string>
|
||||
<!-- Quick action strings -->
|
||||
<!-- Incognito mode strings -->
|
||||
<!-- Settings UI strings -->
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Sajūtu rakstzīmes</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Sajūtu rakstzīmes</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Japāņu sajūtu zīmes (Kaomoji)</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Sajūtu rakstzīmju vēstures lielākais iespējamais lielums</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Vēlamā sajūtu rakstzīmju ādas nokrāsa</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Vēlamais sajūtu rakstzīmju matu sakārtojums</string>
|
||||
<!-- Emoji strings -->
|
||||
@@ -26,10 +25,6 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Priekšmeti</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Zīmes</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Karogi</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Nav nesen izmantotu sajūtu rakstzīmju. Tās parādīsies šeit pēc izmantošanas.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Lai piekļūtu savai emocijzīmju vēsturei, vispirms ir jāatslēdz iekārta.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Lietderīgs padoms: ilgs piespiediens uz nesen izmantotajām sajūtu rakstzīmēm noņems tās no šī skata.</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji} tika noņemta no nesen izmantotajām sajūtu rakstzīmēm</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Uz augšu</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Izpildīt bultu uz augšu</string>
|
||||
@@ -118,6 +113,8 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Vismaz vienam laukam nav atlasīta vērtība. Lūgums norādīt vērtību laukam(iem).</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (nav uzstādīts)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Izkārtojumi</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Izdzēšanas apstiprināšana</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_warning" comment="Warning message in the confirmation dialog to confirm the user's intent to delete">Vai tiešām izdzēst šo apakšveidu?</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">Izskats</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Izskata veids</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Saullēkta laikā</string>
|
||||
@@ -557,6 +554,8 @@
|
||||
<string name="devtools__show_input_state_overlay__summary" comment="Summary of Show input cache overlay in Devtools">Pārklāj pašreizējo ievades stāvokli atkļūdošanai</string>
|
||||
<string name="devtools__show_spelling_overlay__label" comment="Label of Show spelling overlay in Devtools">Rādīt pareizrakstības pārklājumu</string>
|
||||
<string name="devtools__show_spelling_overlay__summary" comment="Summary of Show spelling overlay in Devtools">Pārklāj pašreizējo pareizrakstības iznākumu atkļūdošanai</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__label">Rādīt iekļauto automātiskās aizpildes pārklājumu</string>
|
||||
<string name="devtools__show_inline_autofill_overlay__summary">Pārklāj pašreizējo iekļauto automātiskās aizpildes iznākumu atkļūdošanai</string>
|
||||
<string name="devtools__show_key_touch_boundaries__label" comment="Label of Show key touch boundaries in Devtools">Rādīt taustiņa pieskārienu robežas</string>
|
||||
<string name="devtools__show_key_touch_boundaries__summary" comment="Summary of Show key touch boundaries in Devtools">Izcelt taustiņa pieskārienu robežas sarkanā krāsā</string>
|
||||
<string name="devtools__show_drag_and_drop_helpers__label" comment="Label of Show drag and drop helpers in Devtools">Rādīt vilkšanas un nomešanas palīgus</string>
|
||||
@@ -572,6 +571,11 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Drošie Android iestatījumi</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Sistēmas Android iestatījumi</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Sistēmas darbības vietas</string>
|
||||
<string name="devtools__debuglog__title">Atkļūdošanas žurnāls</string>
|
||||
<string name="devtools__debuglog__copied_to_clipboard">Atkļūdošanas žurnāls tika ievietots starpliktuvē</string>
|
||||
<string name="devtools__debuglog__copy_log">Ievietot žurnālu starpliktuvē</string>
|
||||
<string name="devtools__debuglog__copy_for_github">Ievietot žurnālu starpliktuvē (GitHub formatējums)</string>
|
||||
<string name="devtools__debuglog__loading">Ielādē…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__home__title">Papildinājumi un paplašinājumi</string>
|
||||
<string name="ext__list__ext_theme">Izskata paplašinājumi</string>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emojis</string>
|
||||
<string name="media__tab__emoticons" comment="Tab description for emoticons in the media UI">Emoticons</string>
|
||||
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
|
||||
<string name="prefs__media__emoji_recently_used_max_size">Emoji historiek maximale lengte</string>
|
||||
<string name="prefs__media__emoji_preferred_skin_tone">Gewenste emoji huidskleur</string>
|
||||
<string name="prefs__media__emoji_preferred_hair_style">Gewenste emoji haarstijl</string>
|
||||
<string name="prefs__media__emoji_suggestion__title" comment="Preference group title">Emojisuggesties</string>
|
||||
<!-- Emoji strings -->
|
||||
<string name="emoji__category__smileys_emotion" comment="Emoji category name">Smiley\'s</string>
|
||||
<string name="emoji__category__people_body" comment="Emoji category name">Mannen</string>
|
||||
@@ -26,10 +26,8 @@
|
||||
<string name="emoji__category__objects" comment="Emoji category name">Voorwerpen</string>
|
||||
<string name="emoji__category__symbols" comment="Emoji category name">Symbolen</string>
|
||||
<string name="emoji__category__flags" comment="Emoji category name">Vlaggen</string>
|
||||
<string name="emoji__recently_used__empty_message" comment="Message if no recently used emojis exist">Geen recent gebruikte emoji\'s gevonden. Zodra je emoji\'s begint te typen, verschijnen ze automatisch hier.</string>
|
||||
<string name="emoji__recently_used__phone_locked_message" comment="Message to show if phone is locked">Ontgrendel eerst uw apparaat om toegang te krijgen tot uw emoji-geschiedenis.</string>
|
||||
<string name="emoji__recently_used__removal_tip" comment="Feature discoverability for removal of recently used emojis">Pro tip: Druk lang op recent gebruikte emoji\'s om ze weer uit deze weergave te verwijderen!</string>
|
||||
<string name="emoji__recently_used__removal_success_message" comment="Toast message if user has long pressed emoji in recently used collection to remove it">{emoji} Verwijderd uit recent gebruikte emoji\'s</string>
|
||||
<string name="emoji__history__pinned">Vastgezet</string>
|
||||
<string name="emoji__history__recent">Recent</string>
|
||||
<!-- Quick action strings -->
|
||||
<string name="quick_action__arrow_up" maxLength="12">Pijl omhoog</string>
|
||||
<string name="quick_action__arrow_up__tooltip">Pijl naar boven uitvoeren</string>
|
||||
@@ -117,6 +115,7 @@
|
||||
<string name="settings__localization__subtype_error_fields_no_value" comment="Error message shown in subtype editor if at least one field is set to '- select -' (means no value specified)">Één of meer velden zijn nog niet ingevuld. Kies a.u.b. een optie voor deze velden.</string>
|
||||
<string name="settings__localization__subtype_error_layout_not_installed" comment="Error message shown in subtype list when a layout is not installed, where %s will be replaced by the layout ID">{layout_id} (niet geïnstalleerd)</string>
|
||||
<string name="settings__localization__group_layouts__label" comment="Label of layouts group">Indelingen</string>
|
||||
<string name="settings__localization__subtype_delete_confirmation_title" comment="Title of the subtype delete confirmation dialog">Bevestiging verwijderen</string>
|
||||
<string name="settings__theme__title" comment="Title of the Theme screen">thema</string>
|
||||
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">thema modus</string>
|
||||
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Zonsopgang</string>
|
||||
@@ -547,6 +546,9 @@
|
||||
<string name="devtools__android_settings_secure__title" comment="Title of Android settings (secure) screen">Veilige Android-instellingen</string>
|
||||
<string name="devtools__android_settings_system__title" comment="Title of Android settings (system) screen">Systeem Android-instellingen</string>
|
||||
<string name="devtools__android_locales__title" comment="Title of Android locales screen">Systeemlandinstellingen</string>
|
||||
<string name="devtools__debuglog__title">Foutopsporingslogboek</string>
|
||||
<string name="devtools__debuglog__copy_log">Logboek kopiëren</string>
|
||||
<string name="devtools__debuglog__loading">Laden…</string>
|
||||
<!-- Extension strings -->
|
||||
<string name="ext__list__ext_theme">Thema-extensies</string>
|
||||
<string name="ext__list__ext_keyboard">Toetsenbordextensies</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user