Compare commits

..

12 Commits

Author SHA1 Message Date
Patrick Goldinger
ca4cd38bb2 Release v0.2.2 2020-10-28 23:38:27 +01:00
Patrick Goldinger
7046c500ff Add number and symbol hint for character layout
- If enabled, the first row of the character layout now has a number row
  integrated.
- If enabled, row 2 & 3 of the character layout will have the symbol of
  the corresponding position in the symbol layout.
- In the top-right corner of each key with a hinted character the number
  or symbol will be visible.
- Also: change order of popup keys in the json definition files. The
  first popup of each key is now the most important and will always be
  focused. Then the following popup keys will be filled from left to
  right and from top to bottom.
- Change layout manager to accommodate new hint feature.
- Document KeyData class
- Add license to several files in ime.text.key package.
- Change how layouts are loaded in TextInputManager: all layouts are now
  loaded for all layout types, this is done a) to help with the new hint
  feature. b) to implement subtype-dependent symbol layouts (nyi;
  future plan).
2020-10-28 23:16:06 +01:00
Patrick Goldinger
0374a82f99 Fix UI not updating correctly in clipboard/cursor row
- UI is now queued for redrawing after cursor status has changed
2020-10-26 17:08:19 +01:00
Patrick Goldinger
217acbd6f1 Improve emoji input view layout
- Emoji input layout now fits automatically to the keyboard's height
- Scroll orientation has been changed to vertical which fits the new
  layout better.
2020-10-26 16:50:09 +01:00
Patrick Goldinger
ef27d511be Add NYI tag notice to settings home screen 2020-10-26 15:22:28 +01:00
Patrick Goldinger
f9a4ffa5eb Add bottom offset option to accommodate for curved screens (#20)
This option will default to 0dp (disabled) but can expand up to 24dp.
Located in Settings > Keyboard.
2020-10-23 17:49:05 +02:00
Patrick Goldinger
5533badd19 Add option to turn off auto-capitalization (Fix #21) 2020-10-23 15:52:44 +02:00
Patrick Goldinger
0f1b4b081d Disable swipe velocity threshold preference
Currently the swipe velocity is calculated based on the path and
time of the swipe. The length unit is completely dependent on the
phone's screen and causes different values on different devices.
If a device-independent solution is found this preference will be
enabled again.
2020-10-22 18:50:25 +02:00
Patrick Goldinger
3feae09df0 Add feedback option to CONTRIBUTING.md as mailto links do not work within config.yml 2020-10-21 23:18:28 +02:00
Patrick Goldinger
34bb28d1fc Fix issue config.yml syntax 2020-10-21 23:16:03 +02:00
Patrick Goldinger
551a294b05 Add feedback option to issue creation process
See #22
2020-10-21 22:47:49 +02:00
Patrick Goldinger
671ff1d8b4 Add question issue template / Improve issue creation process 2020-10-19 20:29:08 +02:00
45 changed files with 587 additions and 241 deletions

View File

@@ -1,34 +1,34 @@
---
name: Bug report
about: Create a report to help fix a bug
about: Create a report to help FlorisBoard improve
title: ''
labels: bug
assignees: ''
---
#### Short description of bug
A short but clear and concise description of what the bug is.
<!--
- Describe the bug in a short but concise way.
- If you have a screenshot or screen recording of the bug, link them at
the end of this issue.
- Please search existing bug reports to avoid creating duplicates.
- Thank you for your help in making FlorisBoard better!
-->
#### Steps to reproduce
**Environment information**
- FlorisBoard Version: <!-- e.g. 0.1.0 -->
- Install Source: <!-- Google PlayStore/F-Droid/GitHub/? -->
- Device: <!-- e.g. OnePlus 7T -->
- Android version, ROM: <!-- e.g. 10, Stock -->
**Steps to reproduce**
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
#### Expected behavior
A clear and concise description of what you expected to happen.
#### What happened instead?
A detailed description of what you expected to happen. If you have screenshots or a screen recording, add it here.
#### Additional info
- Version: [e.g. 0.1.0]
- Source: [e.g. Google PlayStore/F-Droid/GitHub/?]
- Device: [e.g. OnePlus 7T]
- Android version, ROM: [e.g. 10, Stock]
#### Log
<!--
```
If applicable, paste the captured debug log here.
```
-->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: General feedback
url: https://github.com/florisboard/florisboard/blob/master/CONTRIBUTING.md
about: Give general feedback about this project

View File

@@ -1,11 +1,19 @@
---
name: Feature request
about: Suggest an idea or enhancement for this project
name: Feature request / Suggestion
about: Suggest an idea for this project
title: ''
labels: proposal
assignees: ''
---
Describe your idea in a short but concise way. If you have multiple ideas which are not directly connected to each other, file an issue per idea. This makes it easy to implement one feature proposal at a time. If you have any examples, e.g. screenshots or other keyboards which have the proposed feature implemented, link them here.
Thank you for your help in making FlorisBoard better!
<!--
- Describe your idea in a short but concise way.
- If you have multiple ideas which are not directly connected to each
other, file an issue per idea. This makes it easy to implement one
feature proposal at a time.
- If you have any examples, e.g. screenshots or other keyboards which
have the proposed feature implemented, link them here.
- Please search existing proposals to avoid creating duplicates.
- Thank you for your help in making FlorisBoard better!
-->

16
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,16 @@
---
name: Question
about: Ask here if you have a question about FlorisBoard
title: ''
labels: question
assignees: ''
---
<!--
- If you need assistance in using FlorisBoard, ask it here!
- If you want to suggest an idea for this project, please use the
Feature request template instead.
- Please search existing questions to avoid creating duplicates.
- Thank you for your help in making FlorisBoard better!
-->

View File

@@ -5,6 +5,12 @@ First off, thanks for considering contributing to FlorisBoard!
There are several ways to contribute to FlorisBoard. This document provides some
general guidelines for each type of contribution.
## Giving general feedback
Either use the review function within Google Play or email me at
[florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev). I
love to hear from you!
## Adding a new feature or making large changes
If you intend to add a new feature or to make large changes, please discuss this
@@ -51,6 +57,7 @@ Notes for tips below:
will get accepted.
### Tips when updating a translation
- To update a translation, check the `strings.xml` in
`app/src/main/res/values` for newly added strings and add them to the
translation file in `app/src/main/res/values-<code>`

View File

@@ -29,12 +29,8 @@ tester, follow these steps:
_C. Use the APK provided in the release section of this repo_
##### Giving feedback
If you want to give feedback to FlorisBoard, there are 2 ways to do so,
as listed below:
- *General feedback:* use the private feedback to developer section on
the PlayStore listing.
- *Bug reports or feature requests:* see the
[contribution guidelines](CONTRIBUTING.md)
If you want to give feedback to FlorisBoard, there are several ways to
do so, as listed in the [contribution guidelines](CONTRIBUTING.md).
Thank you for contributing to FlorisBoard!
@@ -96,9 +92,10 @@ height="256" alt="Preview Image">
### Other useful features
* [x] One-handed mode
* [x] Clipboard/cursor tools
* [x] Integrated number row / symbols in character layouts (0.3.0)
* [ ] Floating keyboard (0.4.0)
* [x] Gesture support (0.3.0)
* [ ] Glide typing (0.3.0)
* [ ] Glide typing (0.4.0)
* [x] Full integration in IME service list of Android (xml/method)
(integration is internal-only, because Android's default subtype
implementation not really allows for dynamic language/layout

View File

@@ -10,8 +10,8 @@ android {
applicationId "dev.patrickgold.florisboard"
minSdkVersion 23
targetSdkVersion 29
versionCode 13
versionName "0.2.1"
versionCode 14
versionName "0.2.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -1,10 +1,10 @@
{
"a": [
{ "code": 229, "label": "å" },
{ "code": 224, "label": "à" },
{ "code": 226, "label": "â" },
{ "code": 227, "label": "ã" },
{ "code": 257, "label": "ā" },
{ "code": 229, "label": "å" },
{ "code": 230, "label": "æ" },
{ "code": 225, "label": "á" },
{ "code": 228, "label": "ä" }
@@ -13,37 +13,37 @@
{ "code": 240, "label": "ð" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 232, "label": "è" },
{ "code": 233, "label": "é" },
{ "code": 235, "label": "ë" },
{ "code": 234, "label": "ê" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 236, "label": "ì" },
{ "code": 303, "label": "į" },
{ "code": 238, "label": "î" },
{ "code": 237, "label": "í" },
{ "code": 239, "label": "ï" }
],
"l": [
{ "code": 322, "label": "ł" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 248, "label": "ø" },
{ "code": 333, "label": "ō" },
{ "code": 339, "label": "œ" },
{ "code": 242, "label": "ò" },
{ "code": 245, "label": "õ" },
{ "code": 244, "label": "ô" },
{ "code": 243, "label": "ó" },
{ "code": 248, "label": "ø" },
{ "code": 246, "label": "ö" }
],
"s": [
@@ -52,9 +52,9 @@
{ "code": 353, "label": "š" }
],
"u": [
{ "code": 250, "label": "ú" },
{ "code": 363, "label": "ū" },
{ "code": 251, "label": "û" },
{ "code": 250, "label": "ú" },
{ "code": 252, "label": "ü" },
{ "code": 249, "label": "ù" }
],
@@ -69,6 +69,7 @@
{ "code": 246, "label": "ö" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -83,14 +84,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,10 +1,10 @@
{
"a": [
{ "code": 228, "label": "ä" },
{ "code": 230, "label": "æ" },
{ "code": 227, "label": "ã" },
{ "code": 229, "label": "å" },
{ "code": 257, "label": "ā" },
{ "code": 228, "label": "ä" },
{ "code": 226, "label": "â" },
{ "code": 224, "label": "à" },
{ "code": 225, "label": "á" }
@@ -13,46 +13,47 @@
{ "code": 231, "label": "ç" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 234, "label": "ê" },
{ "code": 233, "label": "é" },
{ "code": 232, "label": "è" },
{ "code": 235, "label": "ë" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 236, "label": "ì" },
{ "code": 239, "label": "ï" },
{ "code": 237, "label": "í" },
{ "code": 238, "label": "î" },
{ "code": 299, "label": "ī" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 246, "label": "ö" },
{ "code": 333, "label": "ō" },
{ "code": 248, "label": "ø" },
{ "code": 245, "label": "õ" },
{ "code": 339, "label": "œ" },
{ "code": 243, "label": "ó" },
{ "code": 242, "label": "ò" },
{ "code": 246, "label": "ö" },
{ "code": 244, "label": "ô" }
],
"s": [
{ "code": 353, "label": "š" },
{ "code": 223, "label": "ß" },
{ "code": 353, "label": "š" },
{ "code": 347, "label": "ś" }
],
"u": [
{ "code": 252, "label": "ü" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 252, "label": "ü" },
{ "code": 251, "label": "û" },
{ "code": 250, "label": "ú" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -67,14 +68,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,10 +1,10 @@
{
"a": [
{ "code": 224, "label": "à" },
{ "code": 230, "label": "æ" },
{ "code": 227, "label": "ã" },
{ "code": 229, "label": "å" },
{ "code": 257, "label": "ā" },
{ "code": 224, "label": "à" },
{ "code": 225, "label": "á" },
{ "code": 226, "label": "â" },
{ "code": 228, "label": "ä" }
@@ -13,44 +13,45 @@
{ "code": 231, "label": "ç" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 234, "label": "ê" },
{ "code": 233, "label": "é" },
{ "code": 232, "label": "è" },
{ "code": 235, "label": "ë" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 236, "label": "ì" },
{ "code": 239, "label": "ï" },
{ "code": 237, "label": "í" },
{ "code": 238, "label": "î" },
{ "code": 299, "label": "ī" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 243, "label": "ó" },
{ "code": 245, "label": "õ" },
{ "code": 333, "label": "ō" },
{ "code": 339, "label": "œ" },
{ "code": 248, "label": "ø" },
{ "code": 242, "label": "ò" },
{ "code": 246, "label": "ö" },
{ "code": 243, "label": "ó" },
{ "code": 244, "label": "ô" }
],
"s": [
{ "code": 223, "label": "ß" }
],
"u": [
{ "code": 250, "label": "ú" },
{ "code": 363, "label": "ū" },
{ "code": 252, "label": "ü" },
{ "code": 250, "label": "ú" },
{ "code": 251, "label": "û" },
{ "code": 249, "label": "ù" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -65,14 +66,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,43 +1,44 @@
{
"a": [
{ "code": 225, "label": "á" },
{ "code": 229, "label": "å" },
{ "code": 261, "label": "ą" },
{ "code": 230, "label": "æ" },
{ "code": 257, "label": "ā" },
{ "code": 170, "label": "ª" },
{ "code": 225, "label": "á" },
{ "code": 224, "label": "à" },
{ "code": 228, "label": "ä" },
{ "code": 226, "label": "â" },
{ "code": 227, "label": "ã" }
],
"c": [
{ "code": 269, "label": "č" },
{ "code": 231, "label": "ç" },
{ "code": 269, "label": "č" },
{ "code": 263, "label": "ć" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 235, "label": "ë" },
{ "code": 233, "label": "é" },
{ "code": 232, "label": "è" },
{ "code": 234, "label": "ê" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 238, "label": "î" },
{ "code": 303, "label": "į" },
{ "code": 236, "label": "ì" },
{ "code": 237, "label": "í" },
{ "code": 239, "label": "ï" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 243, "label": "ó" },
{ "code": 186, "label": "º" },
{ "code": 333, "label": "ō" },
{ "code": 248, "label": "ø" },
@@ -45,20 +46,20 @@
{ "code": 245, "label": "õ" },
{ "code": 244, "label": "ô" },
{ "code": 246, "label": "ö" },
{ "code": 243, "label": "ó" },
{ "code": 242, "label": "ò" }
],
"s": [
{ "code": 223, "label": "ß" }
],
"u": [
{ "code": 250, "label": "ú" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 250, "label": "ú" },
{ "code": 252, "label": "ü" },
{ "code": 251, "label": "û" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 58, "label": ":" },
{ "code": 38, "label": "&" },
{ "code": 64, "label": "@" },
@@ -73,14 +74,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -34,9 +34,9 @@
{ "code": 1610, "label": "ي" }
],
"ا": [
{ "code": 1570, "label": "آ" },
{ "code": 1649, "label": "ٱ" },
{ "code": 1569, "label": "ء" },
{ "code": 1570, "label": "آ" },
{ "code": 1571, "label": "أ" },
{ "code": 1573, "label": "إ" }
],
@@ -44,8 +44,8 @@
{ "code": 1577, "label": "ة" }
],
"ک": [
{ "code": 1603, "label": "ك" },
{ "code": 1706, "label": "ڪ"}
{ "code": 1706, "label": "ڪ"},
{ "code": 1603, "label": "ك" }
],
"ز": [
{ "code": 1688, "label": "ژ" }
@@ -54,6 +54,7 @@
{ "code": 1572, "label": "ؤ" }
],
".~normal": [
{ "code": 1611, "label": "ً" },
{ "code": 1622, "label": "ٖ" },
{ "code": 1648, "label": "ٰ" },
{ "code": 1619, "label": "ٓ" },
@@ -66,15 +67,14 @@
{ "code": 1617, "label": "ّ" },
{ "code": 1612, "label": "ٌ" },
{ "code": 1613, "label": "ٍ" },
{ "code": 1611, "label": "ً" },
{ "code": 1620, "label": "ٔ" }
],
".~uri": [
{ "code": -255, "label": ".ir"},
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" },
{ "code": -255, "label": ".ir"}
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,39 +1,39 @@
{
"a": [
{ "code": 228, "label": "ä" },
{ "code": 225, "label": "á" },
{ "code": 226, "label": "â" },
{ "code": 227, "label": "ã" },
{ "code": 257, "label": "ā" },
{ "code": 228, "label": "ä" },
{ "code": 229, "label": "å" },
{ "code": 230, "label": "æ" },
{ "code": 224, "label": "à" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 232, "label": "è" },
{ "code": 233, "label": "é" },
{ "code": 235, "label": "ë" },
{ "code": 234, "label": "ê" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 236, "label": "ì" },
{ "code": 303, "label": "į" },
{ "code": 238, "label": "î" },
{ "code": 237, "label": "í" },
{ "code": 239, "label": "ï" }
],
"o": [
{ "code": 246, "label": "ö" },
{ "code": 333, "label": "ō" },
{ "code": 339, "label": "œ" },
{ "code": 243, "label": "ó" },
{ "code": 245, "label": "õ" },
{ "code": 242, "label": "ò" },
{ "code": 244, "label": "ô" },
{ "code": 246, "label": "ö" },
{ "code": 248, "label": "ø" }
],
"s": [
@@ -42,15 +42,15 @@
{ "code": 347, "label": "ś" }
],
"u": [
{ "code": 252, "label": "ü" },
{ "code": 363, "label": "ū" },
{ "code": 251, "label": "û" },
{ "code": 252, "label": "ü" },
{ "code": 250, "label": "ú" },
{ "code": 249, "label": "ù" }
],
"z": [
{ "code": 380, "label": "ż" },
{ "code": 382, "label": "ž" },
{ "code": 380, "label": "ż" },
{ "code": 378, "label": "ź" }
],
"ä": [
@@ -60,6 +60,7 @@
{ "code": 248, "label": "ø" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -74,14 +75,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,42 +1,43 @@
{
"a": [
{ "code": 224, "label": "à" },
{ "code": 227, "label": "ã" },
{ "code": 229, "label": "å" },
{ "code": 257, "label": "ā" },
{ "code": 170, "label": "ª" },
{ "code": 224, "label": "à" },
{ "code": 226, "label": "â" },
{ "code": 230, "label": "æ" },
{ "code": 225, "label": "á" },
{ "code": 228, "label": "ä" }
],
"c": [
{ "code": 269, "label": "č" },
{ "code": 231, "label": "ç" },
{ "code": 269, "label": "č" },
{ "code": 263, "label": "ć" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 234, "label": "ê" },
{ "code": 233, "label": "é" },
{ "code": 232, "label": "è" },
{ "code": 235, "label": "ë" }
],
"i": [
{ "code": 238, "label": "î" },
{ "code": 299, "label": "ī" },
{ "code": 237, "label": "í" },
{ "code": 303, "label": "į" },
{ "code": 236, "label": "ì" },
{ "code": 238, "label": "î" },
{ "code": 239, "label": "ï" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 244, "label": "ô" },
{ "code": 186, "label": "º" },
{ "code": 333, "label": "ō" },
{ "code": 245, "label": "õ" },
@@ -44,18 +45,17 @@
{ "code": 243, "label": "ó" },
{ "code": 242, "label": "ò" },
{ "code": 246, "label": "ö" },
{ "code": 244, "label": "ô" },
{ "code": 339, "label": "œ" }
],
"s": [
{ "code": 353, "label": "š" },
{ "code": 223, "label": "ß" },
{ "code": 353, "label": "š" },
{ "code": 347, "label": "ś" }
],
"u": [
{ "code": 249, "label": "ù" },
{ "code": 363, "label": "ū" },
{ "code": 252, "label": "ü" },
{ "code": 249, "label": "ù" },
{ "code": 251, "label": "û" },
{ "code": 250, "label": "ú" }
],
@@ -63,6 +63,7 @@
{ "code": 255, "label": "ÿ" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -77,14 +78,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,10 +1,10 @@
{
"a": [
{ "code": 225, "label": "á" },
{ "code": 224, "label": "à" },
{ "code": 226, "label": "â" },
{ "code": 227, "label": "ã" },
{ "code": 257, "label": "ā" },
{ "code": 225, "label": "á" },
{ "code": 228, "label": "ä" },
{ "code": 230, "label": "æ" },
{ "code": 229, "label": "å" }
@@ -13,39 +13,39 @@
{ "code": 240, "label": "ð" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 232, "label": "è" },
{ "code": 233, "label": "é" },
{ "code": 235, "label": "ë" },
{ "code": 234, "label": "ê" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 236, "label": "ì" },
{ "code": 303, "label": "į" },
{ "code": 238, "label": "î" },
{ "code": 237, "label": "í" },
{ "code": 239, "label": "ï" }
],
"o": [
{ "code": 243, "label": "ó" },
{ "code": 333, "label": "ō" },
{ "code": 248, "label": "ø" },
{ "code": 245, "label": "õ" },
{ "code": 339, "label": "œ" },
{ "code": 242, "label": "ò" },
{ "code": 244, "label": "ô" },
{ "code": 243, "label": "ó" },
{ "code": 246, "label": "ö" }
],
"t": [
{ "code": 254, "label": "þ" }
],
"u": [
{ "code": 250, "label": "ú" },
{ "code": 363, "label": "ū" },
{ "code": 251, "label": "û" },
{ "code": 250, "label": "ú" },
{ "code": 252, "label": "ü" },
{ "code": 249, "label": "ù" }
],
@@ -54,6 +54,7 @@
{ "code": 255, "label": "ÿ" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -68,14 +69,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,37 +1,38 @@
{
"a": [
{ "code": 224, "label": "à" },
{ "code": 227, "label": "ã" },
{ "code": 229, "label": "å" },
{ "code": 257, "label": "ā" },
{ "code": 170, "label": "ª" },
{ "code": 224, "label": "à" },
{ "code": 225, "label": "á" },
{ "code": 226, "label": "â" },
{ "code": 228, "label": "ä" },
{ "code": 230, "label": "æ" }
],
"e": [
{ "code": 232, "label": "è" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 234, "label": "ê" },
{ "code": 232, "label": "è" },
{ "code": 233, "label": "é" },
{ "code": 235, "label": "ë" }
],
"i": [
{ "code": 236, "label": "ì" },
{ "code": 299, "label": "ī" },
{ "code": 239, "label": "ï" },
{ "code": 303, "label": "į" },
{ "code": 238, "label": "î" },
{ "code": 236, "label": "ì" },
{ "code": 237, "label": "í" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 242, "label": "ò" },
{ "code": 186, "label": "º" },
{ "code": 333, "label": "ō" },
{ "code": 339, "label": "œ" },
@@ -39,17 +40,17 @@
{ "code": 245, "label": "õ" },
{ "code": 246, "label": "ö" },
{ "code": 244, "label": "ô" },
{ "code": 242, "label": "ò" },
{ "code": 243, "label": "ó" }
],
"u": [
{ "code": 249, "label": "ù" },
{ "code": 363, "label": "ū" },
{ "code": 251, "label": "û" },
{ "code": 249, "label": "ù" },
{ "code": 250, "label": "ú" },
{ "code": 252, "label": "ü" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -64,14 +65,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,10 +1,10 @@
{
"a": [
{ "code": 229, "label": "å" },
{ "code": 225, "label": "á" },
{ "code": 226, "label": "â" },
{ "code": 227, "label": "ã" },
{ "code": 257, "label": "ā" },
{ "code": 229, "label": "å" },
{ "code": 230, "label": "æ" },
{ "code": 228, "label": "ä" },
{ "code": 224, "label": "à" }
@@ -13,28 +13,28 @@
{ "code": 231, "label": "ç" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 234, "label": "ê" },
{ "code": 233, "label": "é" },
{ "code": 232, "label": "è" },
{ "code": 235, "label": "ë" }
],
"o": [
{ "code": 248, "label": "ø" },
{ "code": 333, "label": "ō" },
{ "code": 339, "label": "œ" },
{ "code": 243, "label": "ó" },
{ "code": 245, "label": "õ" },
{ "code": 242, "label": "ò" },
{ "code": 244, "label": "ô" },
{ "code": 248, "label": "ø" },
{ "code": 246, "label": "ö" }
],
"u": [
{ "code": 252, "label": "ü" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 252, "label": "ü" },
{ "code": 251, "label": "û" },
{ "code": 250, "label": "ú" }
],
@@ -45,6 +45,7 @@
{ "code": 246, "label": "ö" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -59,14 +60,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,10 +1,10 @@
{
"a": [
{ "code": 229, "label": "å" },
{ "code": 225, "label": "á" },
{ "code": 226, "label": "â" },
{ "code": 227, "label": "ã" },
{ "code": 257, "label": "ā" },
{ "code": 229, "label": "å" },
{ "code": 230, "label": "æ" },
{ "code": 228, "label": "ä" },
{ "code": 224, "label": "à" }
@@ -13,11 +13,11 @@
{ "code": 231, "label": "ç" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 275, "label": "ē" },
{ "code": 281, "label": "ę" },
{ "code": 279, "label": "ė" },
{ "code": 234, "label": "ê" },
{ "code": 233, "label": "é" },
{ "code": 232, "label": "è" },
{ "code": 235, "label": "ë" }
],
@@ -25,19 +25,19 @@
{ "code": 236, "label": "ì" }
],
"o": [
{ "code": 248, "label": "ø" },
{ "code": 333, "label": "ō" },
{ "code": 339, "label": "œ" },
{ "code": 243, "label": "ó" },
{ "code": 245, "label": "õ" },
{ "code": 242, "label": "ò" },
{ "code": 244, "label": "ô" },
{ "code": 248, "label": "ø" },
{ "code": 246, "label": "ö" }
],
"u": [
{ "code": 252, "label": "ü" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 252, "label": "ü" },
{ "code": 251, "label": "û" },
{ "code": 250, "label": "ú" }
],
@@ -51,6 +51,7 @@
{ "code": 246, "label": "ö" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -65,14 +66,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,41 +1,42 @@
{
"a": [
{ "code": 225, "label": "á" },
{ "code": 228, "label": "ä" },
{ "code": 229, "label": "å" },
{ "code": 230, "label": "æ" },
{ "code": 170, "label": "ª" },
{ "code": 225, "label": "á" },
{ "code": 227, "label": "ã" },
{ "code": 224, "label": "à" },
{ "code": 226, "label": "â" }
],
"c": [
{ "code": 263, "label": "ć" },
{ "code": 231, "label": "ç" },
{ "code": 263, "label": "ć" },
{ "code": 269, "label": "č" }
],
"e": [
{ "code": 233, "label": "é" },
{ "code": 235, "label": "ë" },
{ "code": 279, "label": "ė" },
{ "code": 275, "label": "ē" },
{ "code": 232, "label": "è" },
{ "code": 233, "label": "é" },
{ "code": 234, "label": "ê" },
{ "code": 281, "label": "ę" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 299, "label": "ī" },
{ "code": 239, "label": "ï" },
{ "code": 303, "label": "į" },
{ "code": 236, "label": "ì" },
{ "code": 237, "label": "í" },
{ "code": 238, "label": "î" }
],
"n": [
{ "code": 324, "label": "ń" },
{ "code": 241, "label": "ñ" }
{ "code": 241, "label": "ñ" },
{ "code": 324, "label": "ń" }
],
"o": [
{ "code": 243, "label": "ó" },
{ "code": 186, "label": "º" },
{ "code": 333, "label": "ō" },
{ "code": 248, "label": "ø" },
@@ -43,17 +44,17 @@
{ "code": 246, "label": "ö" },
{ "code": 242, "label": "ò" },
{ "code": 244, "label": "ô" },
{ "code": 243, "label": "ó" },
{ "code": 245, "label": "õ" }
],
"u": [
{ "code": 250, "label": "ú" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 250, "label": "ú" },
{ "code": 252, "label": "ü" },
{ "code": 251, "label": "û" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -68,14 +69,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -1,17 +1,17 @@
{
"a": [
{ "code": 228, "label": "ä" },
{ "code": 224, "label": "à" },
{ "code": 226, "label": "â" },
{ "code": 261, "label": "ą" },
{ "code": 227, "label": "ã" },
{ "code": 228, "label": "ä" },
{ "code": 229, "label": "å" },
{ "code": 230, "label": "æ" },
{ "code": 225, "label": "á" }
],
"c": [
{ "code": 269, "label": "č" },
{ "code": 231, "label": "ç" },
{ "code": 269, "label": "č" },
{ "code": 263, "label": "ć" }
],
"d": [
@@ -19,36 +19,36 @@
{ "code": 271, "label": "ď" }
],
"e": [
{ "code": 234, "label": "ê" },
{ "code": 233, "label": "é" },
{ "code": 234, "label": "ê" },
{ "code": 232, "label": "è" },
{ "code": 235, "label": "ë" },
{ "code": 281, "label": "ę" }
],
"i": [
{ "code": 237, "label": "í" },
{ "code": 239, "label": "ï" },
{ "code": 299, "label": "ī" },
{ "code": 303, "label": "į" },
{ "code": 238, "label": "î" },
{ "code": 237, "label": "í" },
{ "code": 236, "label": "ì" }
],
"l": [
{ "code": 322, "label": "ł" }
],
"n": [
{ "code": 328, "label": "ň" },
{ "code": 324, "label": "ń" },
{ "code": 328, "label": "ň" },
{ "code": 241, "label": "ñ" }
],
"o": [
{ "code": 246, "label": "ö" },
{ "code": 333, "label": "ō" },
{ "code": 245, "label": "õ" },
{ "code": 242, "label": "ò" },
{ "code": 244, "label": "ô" },
{ "code": 243, "label": "ó" },
{ "code": 339, "label": "œ" },
{ "code": 246, "label": "ö" },
{ "code": 248, "label": "ø" }
],
"r": [
@@ -65,9 +65,9 @@
{ "code": 254, "label": "þ" }
],
"u": [
{ "code": 252, "label": "ü" },
{ "code": 363, "label": "ū" },
{ "code": 249, "label": "ù" },
{ "code": 252, "label": "ü" },
{ "code": 250, "label": "ú" },
{ "code": 251, "label": "û" }
],
@@ -76,18 +76,19 @@
{ "code": 255, "label": "ÿ" }
],
"z": [
{ "code": 380, "label": "ż" },
{ "code": 378, "label": "ź" },
{ "code": 380, "label": "ż" },
{ "code": 382, "label": "ž" }
],
"ä": [
{ "code": 230, "label": "æ" }
],
"ö": [
{ "code": 339, "label": "œ" },
{ "code": 248, "label": "ø" }
{ "code": 248, "label": "ø" },
{ "code": 339, "label": "œ" }
],
".~normal": [
{ "code": 44, "label": "," },
{ "code": 38, "label": "&" },
{ "code": 37, "label": "%" },
{ "code": 43, "label": "+" },
@@ -102,14 +103,13 @@
{ "code": 41, "label": ")" },
{ "code": 35, "label": "#" },
{ "code": 33, "label": "!" },
{ "code": 44, "label": "," },
{ "code": 63, "label": "?" }
],
".~uri": [
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".gov" },
{ "code": -255, "label": ".edu" },
{ "code": -255, "label": ".org" },
{ "code": -255, "label": ".com" },
{ "code": -255, "label": ".net" }
]
}

View File

@@ -24,6 +24,7 @@ import android.widget.LinearLayout
import android.widget.ViewFlipper
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.util.ViewLayoutUtils
import kotlin.math.roundToInt
/**
@@ -83,11 +84,14 @@ class InputView : LinearLayout {
"extra_tall" -> 1.15f
else -> 1.00f
}
val height = (resources.getDimension(R.dimen.inputView_baseHeight) * heightFactor).roundToInt()
var height = (resources.getDimension(R.dimen.inputView_baseHeight) * heightFactor).roundToInt()
desiredInputViewHeight = height
desiredSmartbarHeight = (0.16129 * height).roundToInt()
desiredTextKeyboardViewHeight = height - desiredSmartbarHeight
desiredMediaKeyboardViewHeight = height
// Add bottom offset for curved screens here. As the desired heights have already been set,
// adding a value to the height now will result in a bottom padding (aka offset).
height += ViewLayoutUtils.convertDpToPixel(florisboard.prefs.keyboard.bottomOffset.toFloat(), context).toInt()
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
}

View File

@@ -180,9 +180,14 @@ class PrefHelper(
*/
class Correction(private val prefHelper: PrefHelper) {
companion object {
const val AUTO_CAPITALIZATION = "correction__auto_capitalization"
const val DOUBLE_SPACE_PERIOD = "correction__double_space_period"
}
var autoCapitalization: Boolean = false
get() = prefHelper.getPref(AUTO_CAPITALIZATION, true)
private set
var doubleSpacePeriod: Boolean = false
get() = prefHelper.getPref(DOUBLE_SPACE_PERIOD, true)
private set
@@ -293,7 +298,10 @@ class PrefHelper(
*/
class Keyboard(private val prefHelper: PrefHelper) {
companion object {
const val BOTTOM_OFFSET = "keyboard__bottom_offset"
const val HEIGHT_FACTOR = "keyboard__height_factor"
const val HINTED_NUMBER_ROW = "keyboard__hinted_number_row"
const val HINTED_SYMBOLS = "keyboard__hinted_symbols"
const val LONG_PRESS_DELAY = "keyboard__long_press_delay"
const val ONE_HANDED_MODE = "keyboard__one_handed_mode"
const val POPUP_ENABLED = "keyboard__popup_enabled"
@@ -303,9 +311,18 @@ class PrefHelper(
const val VIBRATION_STRENGTH = "keyboard__vibration_strength"
}
var bottomOffset: Int = 0
get() = prefHelper.getPref(BOTTOM_OFFSET, 0)
private set
var heightFactor: String = ""
get() = prefHelper.getPref(HEIGHT_FACTOR, "normal")
private set
var hintedNumberRow: Boolean
get() = prefHelper.getPref(HINTED_NUMBER_ROW, true)
set(v) = prefHelper.setPref(HINTED_NUMBER_ROW, v)
var hintedSymbols: Boolean
get() = prefHelper.getPref(HINTED_SYMBOLS, true)
set(v) = prefHelper.setPref(HINTED_SYMBOLS, v)
var longPressDelay: Int = 0
get() = prefHelper.getPref(LONG_PRESS_DELAY, 300)
private set
@@ -341,10 +358,10 @@ class PrefHelper(
}
var activeSubtypeId: Int
get() = prefHelper.getPref(ACTIVE_SUBTYPE_ID, Subtype.DEFAULT.id)
get() = prefHelper.getPref(ACTIVE_SUBTYPE_ID, Subtype.DEFAULT.id)
set(v) = prefHelper.setPref(ACTIVE_SUBTYPE_ID, v)
var subtypes: String
get() = prefHelper.getPref(SUBTYPES, "")
get() = prefHelper.getPref(SUBTYPES, "")
set(v) = prefHelper.setPref(SUBTYPES, v)
}

View File

@@ -61,7 +61,7 @@ class MediaInputView : LinearLayout, FlorisBoard.EventListener {
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val height = florisboard?.inputView?.desiredInputViewHeight ?: 0
val height = florisboard?.inputView?.desiredMediaKeyboardViewHeight ?: 0
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
}
}

View File

@@ -18,14 +18,12 @@ package dev.patrickgold.florisboard.ime.media.emoji
import android.annotation.SuppressLint
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.drawable.Drawable
import android.os.Handler
import android.util.TypedValue
import android.view.Gravity
import android.view.MotionEvent
import android.widget.HorizontalScrollView
import android.widget.ScrollView
import androidx.core.content.ContextCompat
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
@@ -91,7 +89,7 @@ class EmojiKeyView(
osHandler = Handler()
}
osHandler?.postDelayed({
(parent.parent as HorizontalScrollView)
(parent.parent as ScrollView)
.requestDisallowInterceptTouchEvent(true)
emojiKeyboardView.isScrollBlocked = true
emojiKeyboardView.popupManager.show(this)

View File

@@ -21,14 +21,13 @@ import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import android.widget.ViewFlipper
import android.widget.*
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayout
import com.google.android.flexbox.JustifyContent
import com.google.android.material.tabs.TabLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
@@ -55,7 +54,7 @@ class EmojiKeyboardView : LinearLayout, FlorisBoard.EventListener {
private var layouts: Deferred<EmojiLayoutDataMap>
private val mainScope = MainScope()
private val tabLayout: TabLayout
private val uiLayouts = EnumMap<EmojiCategory, HorizontalScrollView>(EmojiCategory::class.java)
private val uiLayouts = EnumMap<EmojiCategory, ScrollView>(EmojiCategory::class.java)
var isScrollBlocked: Boolean = false
var popupManager = KeyPopupManager<EmojiKeyboardView, EmojiKeyView>(this)
@@ -66,12 +65,15 @@ class EmojiKeyboardView : LinearLayout, FlorisBoard.EventListener {
layouts = mainScope.async(Dispatchers.IO) {
parseRawEmojiSpecsFile(context, "ime/media/emoji/emoji-test.txt")
}
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT
)
orientation = VERTICAL
emojiViewFlipper = ViewFlipper(context)
emojiViewFlipper.layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT
)
emojiViewFlipper.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 0).apply {
weight = 1.0f
}
emojiViewFlipper.measureAllChildren = false
addView(emojiViewFlipper)
@@ -117,10 +119,10 @@ class EmojiKeyboardView : LinearLayout, FlorisBoard.EventListener {
*/
private suspend fun buildLayout() = withContext(Dispatchers.Default) {
for (category in EmojiCategory.values()) {
val hsv = buildLayoutForCategory(category)
uiLayouts[category] = hsv
val scrollView = buildLayoutForCategory(category)
uiLayouts[category] = scrollView
withContext(Dispatchers.Main) {
emojiViewFlipper.addView(hsv)
emojiViewFlipper.addView(scrollView)
}
}
}
@@ -130,18 +132,19 @@ class EmojiKeyboardView : LinearLayout, FlorisBoard.EventListener {
* context and will not block the main UI thread.
*
* @param category The category for which a layout should be built.
* @return The layout (top-most view is a [HorizontalScrollView]).
* @return The layout (top-most view is a [ScrollView]).
*/
@SuppressLint("ClickableViewAccessibility")
private suspend fun buildLayoutForCategory(
category: EmojiCategory
): HorizontalScrollView = withContext(Dispatchers.Default) {
val hsv = HorizontalScrollView(context)
hsv.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
): ScrollView = withContext(Dispatchers.Default) {
val scrollView = ScrollView(context)
scrollView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
val flexboxLayout = FlexboxLayout(context)
flexboxLayout.layoutParams =
LayoutParams(LayoutParams.WRAP_CONTENT, emojiKeyHeight * 3)
flexboxLayout.flexDirection = FlexDirection.COLUMN
LayoutParams(LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
flexboxLayout.flexDirection = FlexDirection.ROW
flexboxLayout.justifyContent = JustifyContent.SPACE_BETWEEN
flexboxLayout.flexWrap = FlexWrap.WRAP
for (emojiKeyData in layouts.await()[category].orEmpty()) {
val emojiKeyView =
@@ -151,11 +154,30 @@ class EmojiKeyboardView : LinearLayout, FlorisBoard.EventListener {
)
flexboxLayout.addView(emojiKeyView)
}
hsv.setOnTouchListener { _, _ ->
// Add empty placeholder emojis at the end so the grid view. Below is an illustration how
// the UI looks with and without an placeholder (e = emoji):
// Without placeholder With placeholder
// e e e e e e e e e e e e e e
// ............. .............
// e e e e e e e e e e e e e e
// e e e e e e e e
//
// Based on this SO's answer idea (by La Nube - Luis R. Díaz Muñiz):
// https://stackoverflow.com/a/31478004/6801193
//
// 24 items are chosen here because that's probably the max items that will be shown per
// row, even in landscape mode.
for (n in 0 until 24) {
val gridPlaceholderView = View(context).apply {
layoutParams = LayoutParams(emojiKeyWidth, 0)
}
flexboxLayout.addView(gridPlaceholderView)
}
scrollView.setOnTouchListener { _, _ ->
return@setOnTouchListener isScrollBlocked
}
hsv.addView(flexboxLayout)
return@withContext hsv
scrollView.addView(flexboxLayout)
return@withContext scrollView
}
/**

View File

@@ -30,7 +30,7 @@ import dev.patrickgold.florisboard.util.*
@SuppressLint("ViewConstructor")
class KeyPopupExtendedSingleView(
context: Context, var isActive: Boolean = false
context: Context, val adjustedIndex: Int, var isActive: Boolean = false
) : androidx.appcompat.widget.AppCompatTextView(
context, null, 0
) {

View File

@@ -24,6 +24,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.core.content.ContextCompat.getDrawable
import androidx.core.view.get
import com.google.android.flexbox.FlexboxLayout
import com.google.android.flexbox.JustifyContent
import dev.patrickgold.florisboard.R
@@ -42,7 +43,6 @@ import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardView
* @property keyboardView Reference to the keyboard view to which this manager class belongs to.
*/
class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD) {
private var anchorLeft: Boolean = false
private var anchorRight: Boolean = false
private var anchorOffset: Int = 0
@@ -101,14 +101,14 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
isInitActive: Boolean = false,
isWrapBefore: Boolean = false
): KeyPopupExtendedSingleView? {
val textView = KeyPopupExtendedSingleView(keyView.context, isInitActive)
val textView = KeyPopupExtendedSingleView(keyView.context, k, isInitActive)
val lp = FlexboxLayout.LayoutParams(keyPopupWidth, keyView.measuredHeight)
lp.isWrapBefore = isWrapBefore
textView.layoutParams = lp
textView.gravity = Gravity.CENTER
val textSize = keyboardView.resources.getDimension(R.dimen.key_popup_textSize)
if (keyView is KeyView) {
when (keyView.data.popup[k].code) {
when (keyView.dataPopupWithHint[k].code) {
KeyCode.SETTINGS -> {
textView.iconDrawable = getDrawable(
keyView.context, R.drawable.ic_settings
@@ -129,13 +129,13 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
}
else -> {
textView.setTextSize(
TypedValue.COMPLEX_UNIT_PX, when (keyView.data.popup[k].code) {
TypedValue.COMPLEX_UNIT_PX, when (keyView.dataPopupWithHint[k].code) {
KeyCode.URI_COMPONENT_TLD,
KeyCode.SWITCH_TO_TEXT_CONTEXT -> textSize * 0.6f
else -> textSize
}
)
textView.text = keyView.getComputedLetter(keyView.data.popup[k])
textView.text = keyView.getComputedLetter(keyView.dataPopupWithHint[k])
}
}
} else if (keyView is EmojiKeyView) {
@@ -211,7 +211,7 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
if (keyView is KeyView) {
popupView.findViewById<TextView>(R.id.key_popup_text)?.text = keyView.getComputedLetter()
popupView.findViewById<ImageView>(R.id.key_popup_threedots)?.visibility = when {
keyView.data.popup.isEmpty() -> View.INVISIBLE
keyView.dataPopupWithHint.isEmpty() -> View.INVISIBLE
else -> View.VISIBLE
}
} else if (keyView is EmojiKeyView) {
@@ -256,17 +256,12 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
}
// Anchor left if keyView is in left half of keyboardView, else anchor right
if (keyView is KeyView) {
anchorLeft = keyView.x < keyboardView.measuredWidth / 2
} else if (keyView is EmojiKeyView) {
val hsv = (keyView.parent.parent as HorizontalScrollView)
anchorLeft = (keyView.x - hsv.scrollX) < keyboardView.measuredWidth / 2
}
anchorLeft = keyView.x < keyboardView.measuredWidth / 2
anchorRight = !anchorLeft
// Determine key counts for each row
val n = when (keyView) {
is KeyView -> keyView.data.popup.size
is KeyView -> keyView.dataPopupWithHint.size
is EmojiKeyView -> keyView.data.popup.size
else -> 0
}
@@ -315,17 +310,29 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
// Build UI
popupViewExt.removeAllViews()
val indices = when (keyView) {
is KeyView -> keyView.data.popup.indices
is KeyView -> keyView.dataPopupWithHint.indices
is EmojiKeyView -> keyView.data.popup.indices
else -> IntRange(0, 0)
}
var hasShownFirst = false
for (k in indices) {
val isInitActive =
anchorLeft && (k - row1count == anchorOffset) ||
anchorRight && (k - row1count == row0count - 1 - anchorOffset)
val kk = when (keyView) {
is KeyView -> when {
isInitActive -> {
hasShownFirst = true
0
}
hasShownFirst -> k
else -> k + 1
}
else -> k
}
popupViewExt.addView(
createTextView(
keyView, k, isInitActive, (row1count > 0) && (k - row1count == 0)
keyView, kk, isInitActive, (row1count > 0) && (k - row1count == 0)
)
)
if (isInitActive) {
@@ -441,7 +448,7 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
}
if (keyView is KeyView) {
for (k in keyView.data.popup.indices) {
for (k in keyView.dataPopupWithHint.indices) {
val view = popupViewExt.getChildAt(k)
if (view != null) {
val textView = view as KeyPopupExtendedSingleView
@@ -471,7 +478,13 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
*/
fun getActiveKeyData(keyView: T_KV): KeyData? {
return if (keyView is KeyView) {
keyView.data.popup.getOrNull(activeExtIndex ?: -1) ?: keyView.data
val activeExtIndex = activeExtIndex
if (activeExtIndex != null) {
val singleView = popupViewExt[activeExtIndex] as KeyPopupExtendedSingleView
keyView.dataPopupWithHint.getOrNull(singleView.adjustedIndex) ?: keyView.data
} else {
keyView.data
}
} else {
null
}

View File

@@ -120,17 +120,13 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
override fun onCreate() {
if (BuildConfig.DEBUG) Log.i(this::class.simpleName, "onCreate()")
for (mode in KeyboardMode.values()) {
if (mode == KeyboardMode.CHARACTERS) {
var subtypes = florisboard.subtypeManager.subtypes
if (subtypes.isEmpty()) {
subtypes = listOf(Subtype.DEFAULT)
}
for (subtype in subtypes) {
layoutManager.preloadComputedLayout(mode, subtype)
}
} else {
layoutManager.preloadComputedLayout(mode, florisboard.activeSubtype)
var subtypes = florisboard.subtypeManager.subtypes
if (subtypes.isEmpty()) {
subtypes = listOf(Subtype.DEFAULT)
}
for (subtype in subtypes) {
for (mode in KeyboardMode.values()) {
layoutManager.preloadComputedLayout(mode, subtype)
}
}
smartbarManager = SmartbarManager.getInstance()
@@ -422,13 +418,13 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
/**
* Updates the current caps state according to the [cursorCapsMode], while respecting
* [capsLock] property.
* [capsLock] property and the correction.autoCapitalization preference.
*/
private fun updateCapsState() {
cursorCapsMode = fetchCurrentCursorCapsMode()
editorCapsMode = parseCapsModeFromFlags(florisboard.currentInputEditorInfo.inputType)
if (!capsLock) {
caps = cursorCapsMode != CapsMode.NONE
caps = florisboard.prefs.correction.autoCapitalization && cursorCapsMode != CapsMode.NONE
keyboardViews[activeKeyboardMode]?.invalidateAllKeys()
}
}

View File

@@ -23,7 +23,6 @@ import dev.patrickgold.florisboard.R
import java.lang.Exception
import kotlin.math.*
/**
* Wrapper class which holds all enums, interfaces and classes for detecting a swipe gesture.
*/
@@ -70,14 +69,15 @@ abstract class SwipeGesture {
val diffX = event.x - firstEvent.x
val diffY = event.y - firstEvent.y
val distanceThresholdNV = numericValue(distanceThreshold)
val velocityThresholdNV = numericValue(velocityThreshold)
/*val velocityThresholdNV = numericValue(velocityThreshold)
val velocity =
((convertPixelsToDp(
sqrt(diffX.pow(2) + diffY.pow(2)),
context
) / event.downTime) * 10.0f.pow(8)).toInt()
) / event.downTime) * 10.0f.pow(8)).toInt()*/
clearEventList()
return if ((abs(diffX) > distanceThresholdNV || abs(diffY) > distanceThresholdNV) && velocity >= velocityThresholdNV) {
// return if ((abs(diffX) > distanceThresholdNV || abs(diffY) > distanceThresholdNV) && velocity >= velocityThresholdNV) {
return if ((abs(diffX) > distanceThresholdNV || abs(diffY) > distanceThresholdNV)) {
val direction = detectDirection(diffX.toDouble(), diffY.toDouble())
listener.onSwipe(direction, Type.TOUCH_UP)
} else {
@@ -173,20 +173,6 @@ abstract class SwipeGesture {
VelocityThreshold.VERY_FAST -> context.resources.getInteger(R.integer.gesture_velocity_threshold_very_fast)
}.toDouble()
}
/**
* This method converts device specific pixels to density independent pixels.
*
* Source: https://stackoverflow.com/a/9563438/6801193 (by Muhammad Nabeel Arif)
*
* @param px A value in px (pixels) unit. Which we need to convert into db
* @param context Context to get resources and device specific display metrics
* @return A float value to represent dp equivalent to px value
*/
private fun convertPixelsToDp(px: Float, context: Context): Float {
return px / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
}
interface Listener {

View File

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

View File

@@ -1,8 +1,47 @@
/*
* Copyright (C) 2020 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.text.key
/**
* Data class which describes a single key and its variants.
*
* @property code The UTF-8 encoded code of the character. The code defined here is used as the
* data passed to the system.
* @property label The string used to display the key in the UI. Is not used for the actual data
* passed to the system. Should normally be the exact same as the [code]. Defaults to an empty
* string.
* @property hintedNumber The hinted number which will be dynamically inserted into the long-press
* [popup]. Leave null to disable the hinted popup for this key. The visibility of the hinted number
* is controlled by the preferences. Defaults to null.
* @property hintedSymbol The hinted symbol which will be dynamically inserted into the long-press
* [popup]. Leave null to disable the hinted popup for this key. The visibility of the hinted symbol
* is controlled by the preferences. Defaults to null.
* @property popup List of keys which will be accessible while long pressing the key. Defaults to
* an empty list (no extended popup).
* @property type The type of the key. Some actions require both [code] and [type] to match in order
* to be successfully executed. Defaults to [KeyType.CHARACTER].
* @property variation Controls if the key should only be shown in some contexts (e.g.: url input)
* or if the key should always be visible. Defaults to [KeyVariation.ALL].
*/
data class KeyData(
var code: Int,
var label: String = "",
var hintedNumber: KeyData? = null,
var hintedSymbol: KeyData? = null,
var popup: MutableList<KeyData> = mutableListOf(),
var type: KeyType = KeyType.CHARACTER,
var variation: KeyVariation = KeyVariation.ALL

View File

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

View File

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

View File

@@ -53,7 +53,7 @@ class KeyView(
private val keyboardView: KeyboardView,
val data: KeyData
) : View(keyboardView.context), SwipeGesture.Listener {
val dataPopupWithHint: MutableList<KeyData>
private var isKeyPressed: Boolean = false
set(value) {
field = value
@@ -77,6 +77,16 @@ class KeyView(
textSize = resources.getDimension(R.dimen.key_textSize)
typeface = Typeface.DEFAULT
}
private var hintedLabel: String? = null
private var hintedLabelPaint: Paint = Paint().apply {
alpha = 120
color = 0
isAntiAlias = true
isFakeBoldText = true
textAlign = Paint.Align.CENTER
textSize = resources.getDimension(R.dimen.key_textHintSize)
typeface = Typeface.DEFAULT
}
var florisboard: FlorisBoard? = null
private val swipeGestureDetector = SwipeGesture.Detector(context, this)
@@ -126,6 +136,23 @@ class KeyView(
background = getDrawable(context, R.drawable.shape_rect_rounded)
elevation = 4.0f
var hintKeyData: KeyData? = null
val hintedNumber = data.hintedNumber
if (prefs.keyboard.hintedNumberRow && hintedNumber != null) {
hintKeyData = hintedNumber
}
val hintedSymbol = data.hintedSymbol
if (prefs.keyboard.hintedSymbols && hintedSymbol != null) {
hintKeyData = hintedSymbol
}
dataPopupWithHint = if (hintKeyData == null) {
data.popup.toMutableList()
} else {
val popupList = data.popup.toMutableList()
popupList.add(hintKeyData)
popupList
}
updateKeyPressedBackground()
}
@@ -211,7 +238,7 @@ class KeyView(
osHandler = Handler()
}
osHandler?.postDelayed({
if (data.popup.isNotEmpty()) {
if (dataPopupWithHint.isNotEmpty()) {
keyboardView.popupManager.extend(this)
}
if (data.code == KeyCode.SPACE) {
@@ -484,6 +511,15 @@ class KeyView(
&& data.code != KeyCode.HALF_SPACE && data.code != KeyCode.KESHIDA || data.type == KeyType.NUMERIC
) {
label = getComputedLetter()
val hintedNumber = data.hintedNumber
if (prefs.keyboard.hintedNumberRow && hintedNumber != null) {
hintedLabel = getComputedLetter(hintedNumber)
}
val hintedSymbol = data.hintedSymbol
if (prefs.keyboard.hintedSymbols && hintedSymbol != null) {
hintedLabel = getComputedLetter(hintedSymbol)
}
} else {
when (data.code) {
KeyCode.DELETE -> {
@@ -577,6 +613,9 @@ class KeyView(
}
}
val isPortrait =
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
// Draw drawable
val drawable = drawable
if (drawable != null) {
@@ -608,14 +647,12 @@ class KeyView(
} else {
labelPaint.textSize = resources.getDimension(R.dimen.key_textSize)
}
labelPaint.color = prefs.theme.keyFgColor
labelPaint.alpha = if (keyboardView.computedLayout?.mode == KeyboardMode.CHARACTERS &&
data.code == KeyCode.SPACE) { 120 } else { 255 }
val isPortrait =
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
if (prefs.keyboard.oneHandedMode != "off" && isPortrait) {
labelPaint.textSize *= 0.9f
}
labelPaint.color = prefs.theme.keyFgColor
labelPaint.alpha = if (keyboardView.computedLayout?.mode == KeyboardMode.CHARACTERS &&
data.code == KeyCode.SPACE) { 120 } else { 255 }
val centerX = measuredWidth / 2.0f
val centerY = measuredHeight / 2.0f + (labelPaint.textSize - labelPaint.descent()) / 2
if (label.contains("\n")) {
@@ -627,6 +664,20 @@ class KeyView(
canvas.drawText(label, centerX, centerY, labelPaint)
}
}
// Draw hinted label
val hintedLabel = hintedLabel
if (hintedLabel != null) {
hintedLabelPaint.textSize = resources.getDimension(R.dimen.key_textHintSize)
if (prefs.keyboard.oneHandedMode != "off" && isPortrait) {
hintedLabelPaint.textSize *= 0.9f
}
hintedLabelPaint.color = prefs.theme.keyFgColor
hintedLabelPaint.alpha = 120
val centerX = measuredWidth * 5.0f / 6.0f
val centerY = measuredHeight * 1.0f / 6.0f + (hintedLabelPaint.textSize - hintedLabelPaint.descent()) / 2
canvas.drawText(hintedLabel, centerX, centerY, hintedLabelPaint)
}
}
/**

View File

@@ -22,10 +22,7 @@ import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.text.key.KeyData
import dev.patrickgold.florisboard.ime.text.key.KeyTypeAdapter
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
import dev.patrickgold.florisboard.ime.text.key.KeyVariationAdapter
import dev.patrickgold.florisboard.ime.text.key.*
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
import kotlinx.coroutines.*
import java.util.*
@@ -37,7 +34,7 @@ private typealias KMS = Pair<KeyboardMode, Subtype>
* Class which manages layout loading and caching.
*/
class LayoutManager(private val context: Context) : CoroutineScope by MainScope() {
private val layoutCache: HashMap<KMS, Deferred<ComputedLayoutData>> = hashMapOf()
private val computedLayoutCache: HashMap<KMS, Deferred<ComputedLayoutData>> = hashMapOf()
/**
* Loads the layout for the specified type and name.
@@ -49,6 +46,7 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
if (type == null || name == null) {
return null
}
val rawJsonData: String = try {
context.assets.open("ime/text/$type/$name.json").bufferedReader().use { it.readText() }
} catch (e: Exception) {
@@ -110,7 +108,7 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
* @param extension The extension layout type and name.
* @returns a [ComputedLayoutData] object, regardless of the specified LTNs or errors.
*/
private fun mergeLayouts(
private suspend fun mergeLayoutsAsync(
keyboardMode: KeyboardMode,
subtype: Subtype,
main: LTN? = null,
@@ -194,6 +192,28 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
}
}
// Add hints to keys
if (keyboardMode == KeyboardMode.CHARACTERS) {
val symbolsComputedArrangement = fetchComputedLayoutAsync(KeyboardMode.SYMBOLS, subtype).await().arrangement
for ((r, row) in computedArrangement.withIndex()) {
if (r >= 3) {
break
}
if (symbolsComputedArrangement.getOrNull(r) != null) {
for ((k, key) in row.withIndex()) {
if (key.type == KeyType.CHARACTER) {
val symbol = symbolsComputedArrangement[r].getOrNull(k)
if (r == 0) {
key.hintedNumber = symbol
} else {
key.hintedSymbol = symbol
}
}
}
}
}
}
return ComputedLayoutData(
keyboardMode,
"computed",
@@ -210,7 +230,7 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
* @param keyboardMode The keyboard mode for which the layout should be computed.
* @param subtype The subtype which localizes the computed layout.
*/
private fun computeLayoutFor(
private suspend fun computeLayoutFor(
keyboardMode: KeyboardMode,
subtype: Subtype
): ComputedLayoutData {
@@ -223,6 +243,9 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
main = LTN(LayoutType.CHARACTERS, subtype.layout)
modifier = LTN(LayoutType.CHARACTERS_MOD, "default")
}
KeyboardMode.EDITING -> {
// Layout for this mode is defined in custom layout xml file.
}
KeyboardMode.NUMERIC -> {
main = LTN(LayoutType.NUMERIC, "default")
}
@@ -246,7 +269,7 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
}
}
return mergeLayouts(keyboardMode, subtype, main, modifier, extension)
return mergeLayoutsAsync(keyboardMode, subtype, main, modifier, extension)
}
/**
@@ -263,14 +286,14 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
subtype: Subtype
): Deferred<ComputedLayoutData> {
val kms = KMS(keyboardMode, subtype)
val cachedComputedLayout = layoutCache[kms]
val cachedComputedLayout = computedLayoutCache[kms]
return if (cachedComputedLayout != null) {
cachedComputedLayout
} else {
val computedLayout = async(Dispatchers.IO) {
computeLayoutFor(keyboardMode, subtype)
}
layoutCache[kms] = computedLayout
computedLayoutCache[kms] = computedLayout
computedLayout
}
}
@@ -289,8 +312,8 @@ class LayoutManager(private val context: Context) : CoroutineScope by MainScope(
subtype: Subtype
) {
val kms = KMS(keyboardMode, subtype)
if (layoutCache[kms] == null) {
layoutCache[kms] = async(Dispatchers.IO) {
if (computedLayoutCache[kms] == null) {
computedLayoutCache[kms] = async(Dispatchers.IO) {
computeLayoutFor(keyboardMode, subtype)
}
}

View File

@@ -167,6 +167,7 @@ class SmartbarManager private constructor() : FlorisBoard.EventListener {
smartbarView?.findViewById<View>(R.id.cc_copy)?.isEnabled = isSelectionActive
smartbarView?.findViewById<View>(R.id.cc_paste)?.isEnabled =
florisboard.clipboardManager?.hasPrimaryClip() ?: false
smartbarView?.invalidate()
}
fun deleteCandidateFromDictionary(candidate: String) {

View File

@@ -16,11 +16,14 @@
package dev.patrickgold.florisboard.util
import android.content.Context
import android.util.DisplayMetrics
import android.view.View
import android.view.Window
import android.widget.FrameLayout
import android.widget.LinearLayout
/**
* This file has been taken from the Android LatinIME project. Following modifications were done to
* the original source code:
@@ -71,4 +74,30 @@ object ViewLayoutUtils {
)
}
}
/**
* This method converts dp unit to equivalent pixels, depending on device density.
*
* Source: https://stackoverflow.com/a/9563438/6801193 (by Muhammad Nabeel Arif)
*
* @param dp A value in dp (density independent pixels) unit. Which we need to convert into pixels
* @param context Context to get resources and device specific display metrics
* @return A float value to represent px equivalent to dp depending on device density
*/
fun convertDpToPixel(dp: Float, context: Context): Float {
return dp * (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
/**
* This method converts device specific pixels to density independent pixels.
*
* Source: https://stackoverflow.com/a/9563438/6801193 (by Muhammad Nabeel Arif)
*
* @param px A value in px (pixels) unit. Which we need to convert into db
* @param context Context to get resources and device specific display metrics
* @return A float value to represent dp equivalent to px value
*/
fun convertPixelsToDp(px: Float, context: Context): Float {
return px / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
}
}

View File

@@ -39,6 +39,16 @@
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
style="@style/SettingsCardView">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Note: Preferences tagged with [NYI] are not yet implemented and thus won\'t do anything or do some basic placeholder stuff only. Please do not file a bug report for these."/>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/repo_url_card"
style="@style/SettingsCardView.Clickable">

View File

@@ -18,6 +18,7 @@
<dimen name="key_borderRadius">6dp</dimen>
<dimen name="key_textSize">18sp</dimen>
<dimen name="key_textHintSize">10sp</dimen>
<dimen name="key_numeric_textSize">12sp</dimen>
<dimen name="key_popup_textSize">21sp</dimen>
<dimen name="emoji_key_textSize">22sp</dimen>

View File

@@ -101,6 +101,11 @@
<string name="pref__theme__navBarIsLight_summary">Set to ON for dark or to OFF for light foreground.</string>
<string name="settings__keyboard__title">Keyboard Preferences</string>
<string name="pref__keyboard__group_keys__label">Keys</string>
<string name="pref__keyboard__hinted_number_row__label">Number row</string>
<string name="pref__keyboard__hinted_number_row__summary">First row of character layout hints number row</string>
<string name="pref__keyboard__hinted_symbols__label">Symbols</string>
<string name="pref__keyboard__hinted_symbols__summary">Second and third row of character layout hint symbols</string>
<string name="pref__keyboard__group_layout__label">Layout</string>
<string name="pref__keyboard__one_handed_mode__label">One-handed mode</string>
<string name="pref__keyboard__one_handed_mode__off">Off</string>
@@ -114,6 +119,7 @@
<string name="pref__keyboard__height_factor__mid_tall">Mid-tall</string>
<string name="pref__keyboard__height_factor__tall">Tall</string>
<string name="pref__keyboard__height_factor__extra_tall">Extra-tall</string>
<string name="pref__keyboard__bottom_offset__label">Bottom offset (for curved screens)</string>
<string name="pref__keyboard__group_keypress__label">Key press</string>
<string name="pref__keyboard__sound_enabled__label">Sound on key press</string>
<string name="pref__keyboard__sound_volume__label">Sound volume on key press</string>
@@ -133,6 +139,8 @@
<string name="pref__suggestion__use_pref_words__label">[NYI] Next-word suggestions</string>
<string name="pref__suggestion__use_pref_words__summary">Use previous words for generating suggestions</string>
<string name="pref__correction__title">Corrections</string>
<string name="pref__correction__auto_capitalization__label">Auto-capitalization</string>
<string name="pref__correction__auto_capitalization__summary">Capitalize words based on the current input context</string>
<string name="pref__correction__double_space_period__label">Double-space period</string>
<string name="pref__correction__double_space_period__summary">Tapping twice on spacebar inserts a period followed by a space</string>

View File

@@ -96,14 +96,14 @@
app:title="@string/pref__gestures__delete_key_swipe_left__label"
app:useSimpleSummaryProvider="true"/>
<ListPreference
<!--<ListPreference
app:iconSpaceReserved="false"
android:defaultValue="normal"
app:entries="@array/pref__gestures__swipe_velocity_threshold__entries"
app:entryValues="@array/pref__gestures__swipe_velocity_threshold__values"
app:key="gestures__swipe_velocity_threshold"
app:title="@string/pref__gestures__swipe_velocity_threshold__label"
app:useSimpleSummaryProvider="true"/>
app:useSimpleSummaryProvider="true"/>-->
<ListPreference
app:iconSpaceReserved="false"

View File

@@ -2,6 +2,26 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref__keyboard__group_keys__label">
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="keyboard__hinted_number_row"
app:iconSpaceReserved="false"
app:title="@string/pref__keyboard__hinted_number_row__label"
app:summary="@string/pref__keyboard__hinted_number_row__summary"/>
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="keyboard__hinted_symbols"
app:iconSpaceReserved="false"
app:title="@string/pref__keyboard__hinted_symbols__label"
app:summary="@string/pref__keyboard__hinted_symbols__summary"/>
</PreferenceCategory>
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/pref__keyboard__group_layout__label">
@@ -24,6 +44,17 @@
app:title="@string/pref__keyboard__height_factor__label"
app:useSimpleSummaryProvider="true"/>
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
app:allowDividerAbove="false"
android:defaultValue="0"
app:key="keyboard__bottom_offset"
app:min="0"
app:max="24"
app:iconSpaceReserved="false"
app:title="@string/pref__keyboard__bottom_offset__label"
app:seekBarIncrement="1"
app:unit=" dp"/>
</PreferenceCategory>
<PreferenceCategory

View File

@@ -8,6 +8,7 @@
<SwitchPreferenceCompat
android:defaultValue="false"
app:enabled="false"
app:key="suggestion__enabled"
app:iconSpaceReserved="false"
app:title="@string/pref__suggestion__enabled__label"
@@ -36,6 +37,13 @@
app:iconSpaceReserved="false"
app:title="@string/pref__correction__title">
<SwitchPreferenceCompat
android:defaultValue="true"
app:key="correction__auto_capitalization"
app:iconSpaceReserved="false"
app:title="@string/pref__correction__auto_capitalization__label"
app:summary="@string/pref__correction__auto_capitalization__summary"/>
<SwitchPreferenceCompat
android:defaultValue="true"
app:key="correction__double_space_period"

View File

@@ -0,0 +1,14 @@
- Add number row / underlying symbol support in character layouts
- First row of each character layout has numbers 1-9 and 0 integrated
- Second and third row have symbols according to the symbol layout
- Number row / Underlying symbols can be enabled/disabled seperately
in the preferences
- Add bottom offset option to accommodate for curved screens (#20)
- Add option to turn off auto-capitalization (#21)
- Fix clipboard/cursor UI not updating in Smartbar when text selection
has changed
- Improve emoji layout
- Scroll orientation is now vertical to better scale to different sizes
of the keyboard
- Temporarily remove swipe velocity threshold as it causes gestures to be
ignored in certain circumstances

View File

@@ -0,0 +1,14 @@
- Aggiungere la riga del numero / il supporto del simbolo sottostante nei layout dei caratteri
- La prima riga di ogni disposizione dei caratteri ha i numeri 1-9 e 0 integrati
- La seconda e la terza riga hanno i simboli secondo la disposizione dei simboli
- Riga dei numeri / I simboli sottostanti possono essere abilitati/disabilitati separatamente
nelle preferenze
- Aggiungete l'opzione di offset dal basso per accogliere gli schermi curvi (#20)
- Aggiungere l'opzione per disattivare l'autocapitalizzazione (#21)
- Fix clipboard/cursore UI non aggiornato in Smartbar quando si seleziona il testo
è cambiato
- Migliorare il layout emoji
- L'orientamento di scorrimento è ora verticale per meglio scalare le diverse dimensioni
della tastiera
- Rimuovere temporaneamente la soglia di velocità di strisciata in quanto fa sì che i gesti siano
ignorato in determinate circostanze