Compare commits
214 Commits
v0.3.16
...
v0.4.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2a1e82963 | ||
|
|
0dd1f90c83 | ||
|
|
22b7a675e4 | ||
|
|
74dd67642c | ||
|
|
44f0c9cd89 | ||
|
|
28fdb423b4 | ||
|
|
de169e9d0d | ||
|
|
ffbe7696a4 | ||
|
|
57254e0ebe | ||
|
|
4b671b5794 | ||
|
|
9cd413f2f3 | ||
|
|
777bf48b50 | ||
|
|
11d4ea206d | ||
|
|
8e7311ea01 | ||
|
|
e63186bebc | ||
|
|
17ca0c1cb1 | ||
|
|
c9df7a9f49 | ||
|
|
0e9963bd3b | ||
|
|
2cde597be6 | ||
|
|
5829ff5d07 | ||
|
|
9a7360bfee | ||
|
|
2d42ed1c06 | ||
|
|
031823c81c | ||
|
|
5b8b73ff16 | ||
|
|
80541095fd | ||
|
|
ed7861ec12 | ||
|
|
f6a1a091b5 | ||
|
|
6d7bbc2df7 | ||
|
|
f7b65f788f | ||
|
|
af282693c8 | ||
|
|
5bb7c6f786 | ||
|
|
7e1bce2cea | ||
|
|
1c873e4026 | ||
|
|
964f5d38e5 | ||
|
|
b3c0cf094a | ||
|
|
6c7a4a6fc0 | ||
|
|
45aa02ca1f | ||
|
|
2e8f06232a | ||
|
|
9a2ba678d0 | ||
|
|
4e73e2a2f7 | ||
|
|
2a4b5b6d75 | ||
|
|
e5b51d8572 | ||
|
|
a84df7d07c | ||
|
|
74f062cce7 | ||
|
|
a4f6c0326f | ||
|
|
e66bcc124f | ||
|
|
6b00121a43 | ||
|
|
2813c64101 | ||
|
|
6542d43cf9 | ||
|
|
ac2df6f915 | ||
|
|
fd98df7548 | ||
|
|
d1415d6cfb | ||
|
|
3045e3e930 | ||
|
|
a1b59d6e69 | ||
|
|
1a0bccdf72 | ||
|
|
3529fa8d70 | ||
|
|
aa00eb6e79 | ||
|
|
759a2ac7c7 | ||
|
|
f5e26917c3 | ||
|
|
0d663bd8a1 | ||
|
|
2d9605fbda | ||
|
|
50e2ab4275 | ||
|
|
0708491056 | ||
|
|
44e8a56610 | ||
|
|
158c83c972 | ||
|
|
46cced07c3 | ||
|
|
6597171011 | ||
|
|
26ada18301 | ||
|
|
93ebbbb3de | ||
|
|
215da1c0ab | ||
|
|
b599b807d8 | ||
|
|
deaf3295fd | ||
|
|
0abec78aae | ||
|
|
63fea7ece4 | ||
|
|
f11b3b837b | ||
|
|
6c879c46dc | ||
|
|
407a477c6a | ||
|
|
27af366234 | ||
|
|
b76a25d649 | ||
|
|
8a2189c763 | ||
|
|
c158eabedc | ||
|
|
ff97c6120a | ||
|
|
1314d0da93 | ||
|
|
1d9a5fb552 | ||
|
|
4ef8e7be88 | ||
|
|
a74e1fa489 | ||
|
|
b9f9437fa7 | ||
|
|
36200eba32 | ||
|
|
d8af1a76e7 | ||
|
|
a47a6065df | ||
|
|
f6e58f7534 | ||
|
|
a5dab5fb5a | ||
|
|
9776ac1812 | ||
|
|
099e5678f7 | ||
|
|
3235472e0f | ||
|
|
19b934cb6c | ||
|
|
4b2211b5c0 | ||
|
|
88bd544c90 | ||
|
|
31a01c8d39 | ||
|
|
d29859c6b3 | ||
|
|
4c800f37f0 | ||
|
|
470d302ed2 | ||
|
|
ae2a1db1ef | ||
|
|
94b62b7224 | ||
|
|
8fe84b999a | ||
|
|
da5b316acd | ||
|
|
eb5fdbb08c | ||
|
|
ad73e3894c | ||
|
|
26650d2a00 | ||
|
|
4395eac500 | ||
|
|
90e60a5e03 | ||
|
|
e647e0d248 | ||
|
|
31c046720a | ||
|
|
03b70b43a6 | ||
|
|
de2b3b9433 | ||
|
|
a51f671c3c | ||
|
|
314cdf79bf | ||
|
|
d7137b41fe | ||
|
|
acad9f66a6 | ||
|
|
8d0565854c | ||
|
|
6932fecbbd | ||
|
|
3e6ed3d7b0 | ||
|
|
85e76892b7 | ||
|
|
65cbc4bea3 | ||
|
|
79d177144a | ||
|
|
8cb2b0bfa7 | ||
|
|
201de6a6db | ||
|
|
f65b11bc6d | ||
|
|
86031bb428 | ||
|
|
58f62e1bd5 | ||
|
|
6212e35382 | ||
|
|
c8d0c6269f | ||
|
|
e6f40932ed | ||
|
|
f8af02c400 | ||
|
|
932a7c3126 | ||
|
|
f0c2ac566f | ||
|
|
19224e5f18 | ||
|
|
6c325af80e | ||
|
|
bb82b78cb7 | ||
|
|
eb30eed735 | ||
|
|
3198977143 | ||
|
|
f3b3c21aaa | ||
|
|
0606afbb64 | ||
|
|
5362df02a5 | ||
|
|
3d15bd7f46 | ||
|
|
15e94ecf2c | ||
|
|
ebb3873fe4 | ||
|
|
c1231cd964 | ||
|
|
53ab0a3fa0 | ||
|
|
aeeff67d2e | ||
|
|
4343703eb3 | ||
|
|
5f09bdbce2 | ||
|
|
3a3e3625f2 | ||
|
|
bdf14c1997 | ||
|
|
d6e064ae00 | ||
|
|
1012094568 | ||
|
|
4117537ff2 | ||
|
|
2a72cb70d6 | ||
|
|
b1cd9d9389 | ||
|
|
568dfc973d | ||
|
|
2e74cec0db | ||
|
|
db378159d6 | ||
|
|
50ff2d8f1b | ||
|
|
061495fb27 | ||
|
|
40cb59ddfd | ||
|
|
38affddc9e | ||
|
|
17dcb90473 | ||
|
|
772402b46f | ||
|
|
29bd8a289c | ||
|
|
79d9e73608 | ||
|
|
b04f8d75f3 | ||
|
|
32b1d123d2 | ||
|
|
b576cafaa4 | ||
|
|
312ef93ffc | ||
|
|
a1dda0c247 | ||
|
|
0c36b96922 | ||
|
|
07e92f052b | ||
|
|
244c834de9 | ||
|
|
61b5c2cffd | ||
|
|
1441bd63cb | ||
|
|
e7d0db0fc0 | ||
|
|
a87d340b25 | ||
|
|
3f0d90cb7c | ||
|
|
b9e9f9b122 | ||
|
|
f2d1cf3baf | ||
|
|
cf1112327a | ||
|
|
c2cb28668d | ||
|
|
75f4fcb91a | ||
|
|
3d92bd0584 | ||
|
|
52ca98a14d | ||
|
|
629a73a5cf | ||
|
|
077ec43855 | ||
|
|
3ecd3618cb | ||
|
|
38bc34913b | ||
|
|
c733e5ceea | ||
|
|
e2536ceb92 | ||
|
|
c17b6f073d | ||
|
|
936b177776 | ||
|
|
7d8036fe69 | ||
|
|
6d08d1a265 | ||
|
|
48aba1c055 | ||
|
|
0b3d3317bf | ||
|
|
d1fbdc581b | ||
|
|
044170eb4b | ||
|
|
a7c16b3ceb | ||
|
|
dd12be2275 | ||
|
|
1049bc543a | ||
|
|
5c5ad3cd32 | ||
|
|
6fce521122 | ||
|
|
2af9941ea6 | ||
|
|
9b24f742d1 | ||
|
|
b36bcf7733 | ||
|
|
9559dbdcd6 | ||
|
|
668dd4b5bf |
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1,2 +1,3 @@
|
||||
github: [patrickgold]
|
||||
liberapay: patrickgold
|
||||
custom: ["https://paypal.me/devpatrickgold"]
|
||||
|
||||
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help FlorisBoard improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for your help in making FlorisBoard better!
|
||||
|
||||
Guide to a good bug-report:
|
||||
• Please search existing bug/crash reports reports to avoid creating duplicates.
|
||||
• Give your bug report a good name (no generics like "Error" or "Crash"), so others can easily identify the topic of your issue.
|
||||
• 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.
|
||||
• Also make sure to fill out the environment information. This info is valuable when trying to fix your described bug.
|
||||
-->
|
||||
|
||||
#### Short description
|
||||
Describe the bug in a short but concise way.
|
||||
|
||||
#### Steps to reproduce
|
||||
1. Go to '…'
|
||||
2. Click on '…'
|
||||
3. Scroll down to '…'
|
||||
4. See error
|
||||
|
||||
#### Environment information
|
||||
- FlorisBoard Version: <!-- e.g. 0.X.X -->
|
||||
- Install Source: <!-- Google PlayStore/F-Droid/GitHub/? -->
|
||||
- Device: <!-- e.g. OnePlus 7T -->
|
||||
- Android: <!-- e.g. 10, Stock -->
|
||||
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
64
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Bug Report
|
||||
description: Create a report to help FlorisBoard improve
|
||||
labels:
|
||||
- "bug"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for your help in making FlorisBoard better!
|
||||
Guide to a good bug-report:
|
||||
• Please search existing bug/crash reports reports to avoid creating duplicates.
|
||||
• Give your bug report a good name (no generics like "Error" or "Crash"), so others can easily identify the topic of your issue.
|
||||
• 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.
|
||||
• Also make sure to fill out the environment information. This info is valuable when trying to fix your described bug.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Short description
|
||||
description: Describe the bug in a short but concise way.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
value: |
|
||||
1. Go to '…'
|
||||
2. Click on '…'
|
||||
3. Scroll down to '…'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: florisversion
|
||||
attributes:
|
||||
label: FlorisBoard Version
|
||||
placeholder: e.g. 0.X.X
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: installsource
|
||||
attributes:
|
||||
label: Install Source
|
||||
options:
|
||||
- Google PlayStore
|
||||
- F-Droid
|
||||
- GitHub
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: device
|
||||
attributes:
|
||||
label: Device
|
||||
placeholder: e.g. OnePlus 7T
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: androidversion
|
||||
attributes:
|
||||
label: Android
|
||||
placeholder: e.g. 10, Stock
|
||||
validations:
|
||||
required: true
|
||||
28
.github/ISSUE_TEMPLATE/crash_report.md
vendored
28
.github/ISSUE_TEMPLATE/crash_report.md
vendored
@@ -1,28 +0,0 @@
|
||||
---
|
||||
name: Crash report
|
||||
about: Create a report with a generated crash log attached to help FlorisBoard improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for your help in making FlorisBoard better!
|
||||
|
||||
Guide to a good crash-report:
|
||||
• Please search existing bug/crash reports to avoid creating duplicates.
|
||||
• Give your crash report a good name (no generics like "Error" or "Crash"), so others can easily identify the topic of your issue.
|
||||
• Describe what you were doing what could've led to the crash and whether the crash is random or reproducible.
|
||||
-->
|
||||
|
||||
#### Short description
|
||||
Describe what you were doing that could've led to the crash.
|
||||
|
||||
#### Steps to reproduce
|
||||
1. Go to '…'
|
||||
2. Click on '…'
|
||||
3. Scroll down to '…'
|
||||
4. See crash
|
||||
|
||||
<!-- Paste the generated crash log below -->
|
||||
38
.github/ISSUE_TEMPLATE/crash_report.yml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/crash_report.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Crash report
|
||||
description: Create a report with a generated crash log attached to help FlorisBoard improve
|
||||
labels:
|
||||
- "bug"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for your help in making FlorisBoard better!
|
||||
Guide to a good crash-report:
|
||||
• Please search existing bug/crash reports to avoid creating duplicates.
|
||||
• Give your crash report a good name (no generics like "Error" or "Crash"), so others can easily identify the topic of your issue.
|
||||
• Describe what you were doing what could've led to the crash and whether the crash is random or reproducible.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Short description
|
||||
description: Describe the bug in a short but concise way.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
value: |
|
||||
1. Go to '…'
|
||||
2. Click on '…'
|
||||
3. Scroll down to '…'
|
||||
4. See crash
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: crashlog
|
||||
attributes:
|
||||
label: Crash log
|
||||
description: Paste the generated crash log below
|
||||
validations:
|
||||
required: true
|
||||
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,18 +0,0 @@
|
||||
---
|
||||
name: Feature request / Suggestion
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: proposal
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for your help in making FlorisBoard better!
|
||||
|
||||
Guide to a good feature-request:
|
||||
• Please search existing proposals to avoid creating duplicates.
|
||||
• If you have multiple ideas which are not directly connected to other, file a new issue for each idea. This makes it easier to implement your proposals.
|
||||
• Describe your idea in a short but concise way.
|
||||
• If you have any examples, e.g. screenshots or other keyboards have the proposed feature implemented, feel free to post them after your description.
|
||||
-->
|
||||
22
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Feature request / Suggestion
|
||||
description: Suggest an idea for this project
|
||||
labels:
|
||||
- "proposal"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for your help in making FlorisBoard better!
|
||||
|
||||
Guide to a good feature-request:
|
||||
• Please search existing proposals to avoid creating duplicates.
|
||||
• If you have multiple ideas which are not directly connected to other, file a new issue for each idea. This makes it easier to implement your proposals.
|
||||
• Describe your idea in a short but concise way.
|
||||
• If you have any examples, e.g. screenshots or other keyboards have the proposed feature implemented, feel free to post them after your description.
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: Feature idea
|
||||
description: Please explain your idea in a precise way.
|
||||
validations:
|
||||
required: true
|
||||
23
.github/workflows/android.yml
vendored
23
.github/workflows/android.yml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
- ".editorconfig"
|
||||
- "fastlane/**"
|
||||
- "CONTRIBUTING.md"
|
||||
- "CODE_OF_CONDUCT.md"
|
||||
- "LICENSE"
|
||||
- "README.md"
|
||||
- "ROADMAP.md"
|
||||
@@ -20,20 +21,24 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodules
|
||||
run: git submodule update --init --recursive
|
||||
- name: set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Setup CMake and Ninja
|
||||
uses: lukka/get-cmake@v3.20.1
|
||||
submodules: recursive
|
||||
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
cache: gradle
|
||||
- name: Set up CMake and Ninja
|
||||
uses: lukka/get-cmake@latest
|
||||
- name: Build with Gradle
|
||||
# MUST call gradlew separately because of an OSS license plugin issue.
|
||||
# See https://github.com/google/play-services-plugins/issues/199
|
||||
run: ./gradlew clean && ./gradlew assembleDebug
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: app-debug.apk
|
||||
path: app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -43,3 +43,7 @@ crowdin.properties
|
||||
|
||||
# C++
|
||||
.cxx/
|
||||
|
||||
# Nix stuff
|
||||
.direnv/
|
||||
result
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "app/src/main/icu4c"]
|
||||
path = app/src/main/icu4c
|
||||
url = https://github.com/florisboard/icu4c
|
||||
[submodule "app/src/main/cpp/nlp"]
|
||||
path = app/src/main/cpp/nlp
|
||||
url = https://github.com/florisboard/nlp
|
||||
|
||||
133
CODE_OF_CONDUCT.md
Normal file
133
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
@@ -2,33 +2,26 @@
|
||||
|
||||
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.
|
||||
There are several ways to contribute to FlorisBoard. This document provides some general guidelines for each type of contribution.
|
||||
|
||||
## Giving general feedback
|
||||
|
||||
NEW! You can now [give general feedback](https://github.com/florisboard/florisboard/discussions/new?category=feedback)
|
||||
directly here on GitHub. This is the preferred way to give feedback, as it allows not only for me to read and respond to
|
||||
feedback, but for everyone in this community.
|
||||
You can [give general feedback](https://github.com/florisboard/florisboard/discussions/new?category=feedback) directly here on GitHub. This is the preferred way to give feedback, as it allows not only for me to read and respond to feedback, but for everyone in this community.
|
||||
|
||||
Optionally you can also use the review function within Google Play or email me
|
||||
at [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev). I love to hear from you! Note, that the amount of
|
||||
feedback emails I get is overwhelmingly high - so if I don't answer or answer really late, I apologize - I guarantee
|
||||
though that I read through every email and that I will use every feedback to improve FlorisBoard :)
|
||||
Optionally you can also use the review function within Google Play or email me at [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev). I love to hear from you! Note, that the amount of feedback emails I get is overwhelmingly high - so if I don't answer or answer really late, I apologize - I guarantee though that I read through every email and that I will use every feedback to improve FlorisBoard :)
|
||||
|
||||
## Translations
|
||||
|
||||
To make FlorisBoard accessible in as many languages as possible, the
|
||||
platform [Crowdin](https://crowdin.florisboard.patrickgold.dev) is used to crowdsource and manage translations. This is
|
||||
the only source of translations from now on - **PRs that add/update translations are no longer accepted.** The list of
|
||||
languages in Crowdin covers the top 20 languages, but feel free to email me at
|
||||
[florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev) to request a language and I'll add it.
|
||||
To make FlorisBoard accessible in as many languages as possible, the platform [Crowdin](https://crowdin.florisboard.patrickgold.dev) is used to crowdsource and manage translations. This is
|
||||
the only source of translations from now on - **PRs that add/update translations are no longer accepted.** The list of languages in Crowdin covers the top 20 languages, but feel free to email me at [florisboard@patrickgold.dev](mailto:florisboard@patrickgold.dev) to request a language and I'll add it.
|
||||
|
||||
## Joining the team
|
||||
|
||||
If you want to join the FlorisBoard maintainer/moderator team and be part of this project's journey that's great to hear! For more info see [this announcement](https://github.com/florisboard/florisboard/discussions/2314)!
|
||||
|
||||
## Adding a new feature or making large changes
|
||||
|
||||
If you intend to add a new feature or to make large changes, please discuss this first through a proposal on GitHub.
|
||||
Discussing your idea enables both you and the dev team that we are on the same page before you start on working on your
|
||||
change. If you have any questions, feel free to ask for help at any time!
|
||||
If you intend to add a new feature or to make large changes, please discuss this first through a proposal on GitHub. Discussing your idea enables both you and the dev team that we are on the same page before you start on working on your change. If you have any questions, feel free to ask for help at any time!
|
||||
|
||||
## Adding a new keyboard layout
|
||||
|
||||
@@ -80,8 +73,7 @@ For popups of non-`characters` layout, simply add the popup directly to each key
|
||||
|
||||
## Adding a new dictionary for a language
|
||||
|
||||
Currently the suggestions implementation is highly experimental and not available until 0.4.0, so dictionaries are
|
||||
currently not accepted.
|
||||
Currently any kind of dictionaries are not accepted until the suggestion implementation has been sorted out.
|
||||
|
||||
## Bug reporting
|
||||
|
||||
|
||||
143
LANGUAGEPACKS-CHINESE.md
Normal file
143
LANGUAGEPACKS-CHINESE.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Chinese language pack
|
||||
|
||||
[简体中文翻译点这里](#简体中文翻译)
|
||||
|
||||
[繁体中文翻譯點這裡](#繁体中文翻譯)
|
||||
|
||||
|
||||
## Default barebones Chinese shape-based pack
|
||||
|
||||
Default barebones Chinese shape-based language pack which are always available.
|
||||
|
||||
Please download the [full Chinese language pack](#full-chinese-shape-based-pack) to access input methods such as wubi, quick cangjie, and other versions of these input methods.
|
||||
|
||||
This pack is released under the same license as Florisboard.
|
||||
|
||||
|
||||
## Full Chinese shape-based pack
|
||||
|
||||
Chinese shape-based language pack based on fcitx5-table-extra.
|
||||
|
||||
This pack is released under a separate license. Please visit to download: [TODO: add link to release page](https://)
|
||||
|
||||
:no_entry: :no_entry: **WARNING** :no_entry: :no_entry:
|
||||
|
||||
- **Input methods that include pinyin, jyutping, zhuyin as (auxiliary) functions are only provided for convenience. Currently, FlorisBoard lacks phonetic input algorithms. These functions currently have poor user experience and are not recommended for daily use.**
|
||||
|
||||
The following input methods are included in this language pack:
|
||||
|
||||
- 中文 (中国) [T9笔画] / Chinese (China) [T9]
|
||||
- 中文 (中国) [五笔98] / Chinese (China) [WUBI98]
|
||||
- ~中文 (中国) [五笔98-拼音混打] / Chinese (China) [WUBI98PINYIN]~
|
||||
- 中文 (中国) [五笔98-单字] / Chinese (China) [WUBI98SINGLE]
|
||||
- 中文 (中国) [五笔-大字库] / Chinese (China) [WUBILARGE]
|
||||
- 中文 (中国) [郑码] / Chinese (China) [ZHENGMA]
|
||||
- 中文 (中国) [郑码-大字库] / Chinese (China) [ZHENGMALARGE]
|
||||
- ~中文 (中国) [郑码-拼音混打] / Chinese (China) [ZHENGMAPINYIN]~
|
||||
- ~中文 (香港) [廣東拼音] / Chinese (Hong Kong) [CANTONESE]~
|
||||
- ~中文 (香港) [港式廣東話] / Chinese (Hong Kong) [CANTONHK]~
|
||||
- 中文 (香港) [輕鬆-大字庫] / Chinese (Hong Kong) [EASYLARGE]
|
||||
- ~中文 (香港) [粤語拼音-表格] / Chinese (Hong Kong) [JYUTPINGTABLE]~
|
||||
- 中文 (香港) [速成三代] / Chinese (Hong Kong) [QUICK3]
|
||||
- 中文 (香港) [經典速成] / Chinese (Hong Kong) [QUICKCLASSIC]
|
||||
- 中文 (香港) [筆順五碼] / Chinese (Hong Kong) [STROKE5]
|
||||
- 中文 (台灣) [行列] / Chinese (Taiwan) [ARRAY30]
|
||||
- 中文 (台灣) [行列-大字库] / Chinese (Taiwan) [ARRAY30LARGE]
|
||||
- 中文 (台灣) [嘸蝦米] / Chinese (Taiwan) [BOSHIAMY]
|
||||
- 中文 (台灣) [倉頡三代] / Chinese (Taiwan) [CANGJIE3]
|
||||
- 中文 (台灣) [倉頡五代] / Chinese (Taiwan) [CANGJIE5]
|
||||
- 中文 (台灣) [倉頡-大字庫] / Chinese (Taiwan) [CANGJIELARGE]
|
||||
- 中文 (台灣) [速成五代] / Chinese (Taiwan) [QUICK5]
|
||||
- 中文 (台灣) [快倉六] / Chinese (Taiwan) [SCJ6]
|
||||
- ~中文 (台灣) [吳語注音] / Chinese (Taiwan) [WU]~
|
||||
|
||||
Third-party license: [https://github.com/fcitx/fcitx5-table-extra/blob/master/LICENSES/GPL-3.0-or-later.txt]
|
||||
|
||||
# 简体中文翻译
|
||||
## 默认中文形码语言包
|
||||
|
||||
请下载[完整中文语言包](#fcitx5-中文形码语言包)来获得五笔、快速仓颉等输入法,及这些输入法的其他版本。
|
||||
|
||||
这一语言包的使用许可与FlorisBoard相同。
|
||||
|
||||
## Fcitx5 中文形码语言包
|
||||
|
||||
这一语言包由另一使用许可提供。下载请访问:[TODO: add link to release page](https://)
|
||||
|
||||
:no_entry: :no_entry: **注意** :no_entry: :no_entry:
|
||||
|
||||
- **含拼音、粤拼、注音等功能的输入法,仅为便利提供。目前,FlorisBoard缺乏音码输入算法,这些功能目前使用体验不佳,暂不推荐日常使用。**
|
||||
|
||||
语言包内含以下输入法:
|
||||
|
||||
- 中文 (中国) [T9笔画] / Chinese (China) [T9]
|
||||
- 中文 (中国) [五笔98] / Chinese (China) [WUBI98]
|
||||
- ~中文 (中国) [五笔98-拼音混打] / Chinese (China) [WUBI98PINYIN]~
|
||||
- 中文 (中国) [五笔98-单字] / Chinese (China) [WUBI98SINGLE]
|
||||
- 中文 (中国) [五笔-大字库] / Chinese (China) [WUBILARGE]
|
||||
- 中文 (中国) [郑码] / Chinese (China) [ZHENGMA]
|
||||
- 中文 (中国) [郑码-大字库] / Chinese (China) [ZHENGMALARGE]
|
||||
- ~中文 (中国) [郑码-拼音混打] / Chinese (China) [ZHENGMAPINYIN]~
|
||||
- ~中文 (香港) [廣東拼音] / Chinese (Hong Kong) [CANTONESE]~
|
||||
- ~中文 (香港) [港式廣東話] / Chinese (Hong Kong) [CANTONHK]~
|
||||
- 中文 (香港) [輕鬆-大字庫] / Chinese (Hong Kong) [EASYLARGE]
|
||||
- ~中文 (香港) [粤語拼音-表格] / Chinese (Hong Kong) [JYUTPINGTABLE]~
|
||||
- 中文 (香港) [速成三代] / Chinese (Hong Kong) [QUICK3]
|
||||
- 中文 (香港) [經典速成] / Chinese (Hong Kong) [QUICKCLASSIC]
|
||||
- 中文 (香港) [筆順五碼] / Chinese (Hong Kong) [STROKE5]
|
||||
- 中文 (台灣) [行列] / Chinese (Taiwan) [ARRAY30]
|
||||
- 中文 (台灣) [行列-大字库] / Chinese (Taiwan) [ARRAY30LARGE]
|
||||
- 中文 (台灣) [嘸蝦米] / Chinese (Taiwan) [BOSHIAMY]
|
||||
- 中文 (台灣) [倉頡三代] / Chinese (Taiwan) [CANGJIE3]
|
||||
- 中文 (台灣) [倉頡五代] / Chinese (Taiwan) [CANGJIE5]
|
||||
- 中文 (台灣) [倉頡-大字庫] / Chinese (Taiwan) [CANGJIELARGE]
|
||||
- 中文 (台灣) [速成五代] / Chinese (Taiwan) [QUICK5]
|
||||
- 中文 (台灣) [快倉六] / Chinese (Taiwan) [SCJ6]
|
||||
- ~中文 (台灣) [吳語注音] / Chinese (Taiwan) [WU]~
|
||||
|
||||
第三方许可证: [https://github.com/fcitx/fcitx5-table-extra/blob/master/LICENSES/GPL-3.0-or-later.txt]
|
||||
|
||||
|
||||
# 繁体中文翻譯
|
||||
## 預設中文形碼語言包
|
||||
|
||||
請下載[完整中文語言包](#fcitx5-中文形碼語言包)來獲得五筆、快速倉頡等輸入法,及這些輸入法的其他版本。
|
||||
|
||||
這一語言包的使用許可與FlorisBoard相同。
|
||||
|
||||
## Fcitx5 中文形碼語言包
|
||||
|
||||
這一語言包由另一使用許可提供。下載請訪問:[TODO: add link to release page](https://)
|
||||
|
||||
:no_entry: :no_entry: **注意** :no_entry: :no_entry:
|
||||
|
||||
- **含拼音、粵拼、注音等功能的輸入法,僅為便利提供。目前,FlorisBoard缺乏音碼輸入算法,這些功能目前使用體驗不佳,暫不推薦日常使用。**
|
||||
|
||||
語言包內含以下輸入法:
|
||||
|
||||
- 中文 (中国) [T9笔画] / Chinese (China) [T9]
|
||||
- 中文 (中国) [五笔98] / Chinese (China) [WUBI98]
|
||||
- ~中文 (中国) [五笔98-拼音混打] / Chinese (China) [WUBI98PINYIN]~
|
||||
- 中文 (中国) [五笔98-单字] / Chinese (China) [WUBI98SINGLE]
|
||||
- 中文 (中国) [五笔-大字库] / Chinese (China) [WUBILARGE]
|
||||
- 中文 (中国) [郑码] / Chinese (China) [ZHENGMA]
|
||||
- 中文 (中国) [郑码-大字库] / Chinese (China) [ZHENGMALARGE]
|
||||
- ~中文 (中国) [郑码-拼音混打] / Chinese (China) [ZHENGMAPINYIN]~
|
||||
- ~中文 (香港) [廣東拼音] / Chinese (Hong Kong) [CANTONESE]~
|
||||
- ~中文 (香港) [港式廣東話] / Chinese (Hong Kong) [CANTONHK]~
|
||||
- 中文 (香港) [輕鬆-大字庫] / Chinese (Hong Kong) [EASYLARGE]
|
||||
- ~中文 (香港) [粤語拼音-表格] / Chinese (Hong Kong) [JYUTPINGTABLE]~
|
||||
- 中文 (香港) [速成三代] / Chinese (Hong Kong) [QUICK3]
|
||||
- 中文 (香港) [經典速成] / Chinese (Hong Kong) [QUICKCLASSIC]
|
||||
- 中文 (香港) [筆順五碼] / Chinese (Hong Kong) [STROKE5]
|
||||
- 中文 (台灣) [行列] / Chinese (Taiwan) [ARRAY30]
|
||||
- 中文 (台灣) [行列-大字库] / Chinese (Taiwan) [ARRAY30LARGE]
|
||||
- 中文 (台灣) [嘸蝦米] / Chinese (Taiwan) [BOSHIAMY]
|
||||
- 中文 (台灣) [倉頡三代] / Chinese (Taiwan) [CANGJIE3]
|
||||
- 中文 (台灣) [倉頡五代] / Chinese (Taiwan) [CANGJIE5]
|
||||
- 中文 (台灣) [倉頡-大字庫] / Chinese (Taiwan) [CANGJIELARGE]
|
||||
- 中文 (台灣) [速成五代] / Chinese (Taiwan) [QUICK5]
|
||||
- 中文 (台灣) [快倉六] / Chinese (Taiwan) [SCJ6]
|
||||
- ~中文 (台灣) [吳語注音] / Chinese (Taiwan) [WU]~
|
||||
|
||||
第三方許可證: [https://github.com/fcitx/fcitx5-table-extra/blob/master/LICENSES/GPL-3.0-or-later.txt]
|
||||
16
LANGUAGEPACKS.md
Normal file
16
LANGUAGEPACKS.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Language Packs
|
||||
|
||||
## Languages
|
||||
|
||||
- [Summary](#summary)
|
||||
- [Chinese / 中文](LANGUAGEPACKS-CHINESE.md)
|
||||
|
||||
## Summary
|
||||
|
||||
Stub.
|
||||
|
||||
This page should describe how language packs work, how to import them, and point to the location of downloadable
|
||||
language packs.
|
||||
|
||||
The homepage of default language packs included in FlorisBoard should link to this page.
|
||||
|
||||
19
README.md
19
README.md
@@ -1,12 +1,14 @@
|
||||
<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) 
|
||||
# FlorisBoard [](https://crowdin.florisboard.patrickgold.dev) [](https://matrix.to/#/#florisboard:matrix.org) [](CODE_OF_CONDUCT.md) 
|
||||
|
||||
**FlorisBoard** is a free and open-source keyboard for Android 7.0+
|
||||
devices. It aims at being modern, user-friendly and customizable while
|
||||
fully respecting your privacy. Currently in early-beta state.
|
||||
|
||||
*Note: Due to various reasons development has been quite stuck in the past year, but things are slowly improving again and new releases/features will follow in the near future, please see the [roadmap](ROADMAP.md) for details!*
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th align="center" width="50%">
|
||||
@@ -18,10 +20,10 @@ fully respecting your privacy. Currently in early-beta state.
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<p><i>Major versions only, 1 release per 1-5 months</i><br><br>Updates are more polished, new features are matured and tested through to ensure a stable experience.</p>
|
||||
<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>Beta versions, up to 1-2 releases per week</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>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>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -54,17 +56,16 @@ 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 and enter the public beta on Google Play.
|
||||
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
|
||||
- Spell checking service
|
||||
- Glide typing (currently English only)
|
||||
|
||||
Word suggestions are not included in the current releases and are a major goal for the v0.4.0 milestone.
|
||||
Word suggestions/spell checking are not included in the current releases and are a major goal for the v0.5.0 milestone.
|
||||
|
||||
Feature roadmap: See [ROADMAP.md](ROADMAP.md)
|
||||
|
||||
@@ -96,14 +97,12 @@ to get more information on this topic.
|
||||
[Kotlin](https://github.com/Kotlin)
|
||||
* [ICU4C](https://github.com/unicode-org/icu) by
|
||||
[The Unicode Consortium](https://github.com/unicode-org)
|
||||
* [Nuspell](https://github.com/nuspell/nuspell) by
|
||||
[Nuspell](https://github.com/nuspell)
|
||||
|
||||
Many thanks to [Nikolay Anzarov](https://www.behance.net/nikolayanzarov) ([@BloodRaven0](https://github.com/BloodRaven0)) for designing and providing the main app icons to this project!
|
||||
|
||||
## License
|
||||
```
|
||||
Copyright 2020-2022 Patrick Goldinger
|
||||
Copyright 2020-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.
|
||||
|
||||
85
ROADMAP.md
85
ROADMAP.md
@@ -1,75 +1,68 @@
|
||||
# Roadmap
|
||||
|
||||
# FlorisBoard's feature roadmap & milestones
|
||||
This feature roadmap intents to provide transparency to what is planned to be added to FlorisBoard in the foreseeable future. Note that there are no ETAs for any version milestones down below, experience has shown these won't hold anyways.
|
||||
|
||||
This feature roadmap intents to provide transparency to what I want to add to FlorisBoard in the foreseeable future.
|
||||
Note that there are no ETAs for any version milestones down below, experience says these won't hold anyways.
|
||||
Each major milestone has associated alpha/beta releases, so if you are interested in previewing features quicker, keep an eye out! Each major 0.x release has also patch releases after the initial major release, which will be published on both the stable and beta tracks.
|
||||
|
||||
I try my best to release regularly, though some features take a lot longer than others and thus releases can be spaced
|
||||
out a bit on the stable track. If you are interested in following the development more closely, make sure to follow
|
||||
along the beta track releases! These are generally more unstable but you get new stuff faster and can provide early
|
||||
feedback, which helps a lot!
|
||||
## 0.4
|
||||
|
||||
## 0.3.x
|
||||
**Main focus**: Getting the project back on track, see [this announcement](https://github.com/florisboard/florisboard/discussions/2314) for details. Note that this has also replaced the previous roadmap, however this step is necessary for getting the project back on track again.
|
||||
|
||||
Releases in this section still follow the old versioning scheme, meaning the patch number is a feature upgrade. As this
|
||||
naming convention is more confusing than useful, beginning with v0.4.0 development a new release/development cycle will
|
||||
be introduced.
|
||||
This includes, but is not exclusive to:
|
||||
- Fixing the most reported bugs/issues
|
||||
- Merging in the Material You theme PR -> Adds Material You support (v0.4.0-alpha05)
|
||||
- Merging in other external PRs as best as possible
|
||||
- Reworking the Settings UI warning boxes and hiding any UI for features related to word suggestions until they are ready
|
||||
- Remove existing glide/swipe typing (see 0.5 milestone)
|
||||
- Fix compilation issues introduced with the 0.4 alphas as best as possible
|
||||
|
||||
### 0.3.15 & 0.3.16 (currently 0.3.15 done, 0.3.16 in work)
|
||||
Maybe in this release, but no guarantee and may be delayed to 0.5:
|
||||
- Develop usable preview of an on-device statistical word suggestion algorithm (see the main [NLP project](https://github.com/florisboard/nlp) for details)
|
||||
- Add experimental plugin system which supports communication with the aforementioned native suggestion algorithm
|
||||
- Include precompiled dictionaries for major languages: English (US/UK), German, Spanish, French, Italian & Russian
|
||||
|
||||
- Hotfix releases for possible bugs in the preference rework (in work)
|
||||
- Lots and lots of bug fixing in general (in work)
|
||||
- Preparation work for 0.4.0, fixing text state logic and use break iterator (done)
|
||||
- Reducing or getting rid of input lag some devices experience (done)
|
||||
- Clean up of project structure for better future development (done)
|
||||
Note that the previous versioning scheme has been dropped in favor of using a major.minor.patch versioning scheme, so versions like `0.3.16` are a thing of the past :)
|
||||
|
||||
## 0.4.0
|
||||
## 0.5
|
||||
|
||||
- Re-adding word suggestions (at least for Latin-based languages at first)
|
||||
- Importing the dictionaries as well as management relies on the Flex extension core and UI in Kotlin
|
||||
- Actually parsing and generating suggestions happens in C++ to avoid another OOM catastrophe like in 0.3.9/10
|
||||
- The actual format of the dictionary and word list source is not decided yet
|
||||
- Community repository on GitHub for theme sharing across users (may be 0.5.0)
|
||||
- New text processing logic
|
||||
- RFC document with technical details will be released later
|
||||
- New keyboard layout engine + file syntax based on the upcoming Unicode Keyboard v3 standard
|
||||
- RFC document with technical details will be released later
|
||||
- Add Tablet mode / Optimizations for landscape input based on new keyboard layout engine
|
||||
- Reimplementation of glide typing with the new layout engine and word suggestion core
|
||||
- Add support for any remaining new features introduced with Android 13
|
||||
|
||||
With this release the versioning scheme changes: the second number now indicates new features, changes in the third "
|
||||
patch" number now indicates bug fixes and minor feature additions for the stable track. The development cycle for each
|
||||
0.x release will have `-alphaXX` (optional and only for large releases), `-betaXX` and `-rcXX` (release candidate)
|
||||
releases on the beta track for interested people to follow along the development. The first release to follow the new
|
||||
scheme will be `0.4.0-alpha01` on the beta track.
|
||||
|
||||
## 0.5.0
|
||||
## 0.6
|
||||
|
||||
- Complete rework of the Emoji panel
|
||||
- Recently used / Emoji history (already implemented with 0.3.14)
|
||||
- Emoji search
|
||||
- Emoji suggestions when using :emoji_name: syntax
|
||||
- Kaomoji panel implementation (the third tab which currently has "not yet implemented")
|
||||
- Smartbar customization improvements
|
||||
- Quick actions customization (order and which buttons to show)
|
||||
- Prepare FlorisBoard repository and app store presence for public beta release on Google Play (will go live with stable
|
||||
0.5.0!!)
|
||||
- Recently used / Emoji history (already implemented with 0.3.14)
|
||||
- Emoji search
|
||||
- Emoji suggestions when using :emoji_name: syntax
|
||||
- Kaomoji panel implementation (the third tab which currently has "not yet implemented")
|
||||
- Maybe: consider upgrading to emoji2 for better unified system-wide emoji styles)
|
||||
- Prepare FlorisBoard repository and app store presence for public beta release on Google Play (will go live with stable 0.6)
|
||||
- Rework branding images and texts of FlorisBoard for the app stores
|
||||
- Focus on stability and experience improvements of the app and keyboard
|
||||
- Add support for new features introduced with Android 14
|
||||
- Not finalized, but planned: raise minimum required Android version from Android 7 (SDK level 24) to Android 8 (SDK level 26)
|
||||
|
||||
## 0.6.0
|
||||
## Backlog / Planned (unassigned)
|
||||
|
||||
**Features that MAY be added (even in versions mentioned above) or dismissed**
|
||||
|
||||
- Upgrade Settings UI to Material 3
|
||||
- Full on-board layout editor which allows users to create their own layouts without writing a JSON file
|
||||
- Import/Export of custom layout files packed in Flex extensions
|
||||
|
||||
## Backlog / Features that MAY be added, even in versions not mentioned above if the feature implementation fits perfectly with another feature
|
||||
|
||||
- Theme rework part II
|
||||
- Adaptive themes v2
|
||||
- Voice-to-text with Mozilla's open-source voice service
|
||||
- Voice-to-text with Mozilla's open-source voice service (or any other oss voice provider)
|
||||
- Text translation
|
||||
- Glide typing better word detection
|
||||
- Proximity-based key typo detection
|
||||
- Floating keyboard
|
||||
- Tablet mode / Optimizations for landscape input
|
||||
- Stickers/GIFs
|
||||
- FlorisBoard landing web page for presentation
|
||||
- Implementing additional layouts
|
||||
- Support for Tasker/Automate/MacroDroid plugins
|
||||
- Support for WearOS/Smartwatches
|
||||
- Handwriting
|
||||
- ...
|
||||
|
||||
2
app/.gitignore
vendored
Normal file
2
app/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Exclude auto-generated icu4c assets
|
||||
src/main/assets/icu4c/
|
||||
@@ -14,11 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Suppress needed until https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
|
||||
@file:Suppress("DSL_SCOPE_VIOLATION")
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.agp.application)
|
||||
@@ -29,11 +25,20 @@ plugins {
|
||||
alias(libs.plugins.mikepenz.aboutlibraries)
|
||||
}
|
||||
|
||||
val projectMinSdk: String by project
|
||||
val projectTargetSdk: String by project
|
||||
val projectCompileSdk: String by project
|
||||
val projectBuildToolsVersion: String by project
|
||||
val projectNdkVersion: String by project
|
||||
val projectVersionCode: String by project
|
||||
val projectVersionName: String by project
|
||||
val projectVersionNameSuffix: String by project
|
||||
|
||||
android {
|
||||
namespace = "dev.patrickgold.florisboard"
|
||||
compileSdk = 31
|
||||
buildToolsVersion = "31.0.0"
|
||||
ndkVersion = "22.1.7171670"
|
||||
compileSdk = projectCompileSdk.toInt()
|
||||
buildToolsVersion = projectBuildToolsVersion
|
||||
ndkVersion = projectNdkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
@@ -44,18 +49,17 @@ android {
|
||||
jvmTarget = "1.8"
|
||||
freeCompilerArgs = listOf(
|
||||
"-Xallow-result-return-type",
|
||||
"-Xopt-in=kotlin.RequiresOptIn",
|
||||
"-Xopt-in=kotlin.contracts.ExperimentalContracts",
|
||||
"-Xjvm-default=compatibility",
|
||||
"-opt-in=kotlin.contracts.ExperimentalContracts",
|
||||
"-Xjvm-default=all-compatibility",
|
||||
)
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "dev.patrickgold.florisboard"
|
||||
minSdk = 24
|
||||
targetSdk = 31
|
||||
versionCode = 86
|
||||
versionName = "0.3.16"
|
||||
minSdk = projectMinSdk.toInt()
|
||||
targetSdk = projectTargetSdk.toInt()
|
||||
versionCode = projectVersionCode.toInt()
|
||||
versionName = projectVersionName
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -69,9 +73,14 @@ android {
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cFlags("-fvisibility=hidden", "-DU_STATIC_IMPLEMENTATION=1")
|
||||
cppFlags("-fvisibility=hidden", "-std=c++17", "-fexceptions", "-ffunction-sections", "-fdata-sections", "-DU_DISABLE_RENAMING=1", "-DU_STATIC_IMPLEMENTATION=1")
|
||||
arguments("-DANDROID_STL=c++_static")
|
||||
targets("florisboard-native")
|
||||
cppFlags("-std=c++20", "-stdlib=libc++")
|
||||
arguments(
|
||||
"-DCMAKE_ANDROID_API=" + minSdk.toString(),
|
||||
"-DICU_ASSET_EXPORT_DIR=" + project.file("src/main/assets/icu4c").absolutePath,
|
||||
"-DBUILD_SHARED_LIBS=false",
|
||||
"-DANDROID_STL=c++_static",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +91,7 @@ android {
|
||||
sourceSets {
|
||||
maybeCreate("main").apply {
|
||||
assets {
|
||||
srcDirs("src/main/assets", "src/main/icu4c/prebuilt/assets")
|
||||
}
|
||||
jniLibs {
|
||||
srcDirs("src/main/icu4c/prebuilt/jniLibs")
|
||||
srcDirs("src/main/assets")
|
||||
}
|
||||
java {
|
||||
srcDirs("src/main/kotlin")
|
||||
@@ -104,11 +110,12 @@ android {
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = libs.versions.androidx.compose.get()
|
||||
kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get()
|
||||
}
|
||||
|
||||
externalNativeBuild {
|
||||
@@ -138,7 +145,7 @@ android {
|
||||
|
||||
create("beta") {
|
||||
applicationIdSuffix = ".beta"
|
||||
versionNameSuffix = ""
|
||||
versionNameSuffix = projectVersionNameSuffix
|
||||
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
isMinifyEnabled = true
|
||||
@@ -151,6 +158,8 @@ android {
|
||||
}
|
||||
|
||||
named("release") {
|
||||
versionNameSuffix = projectVersionNameSuffix
|
||||
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
@@ -191,15 +200,20 @@ tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.accompanist.flowlayout)
|
||||
implementation(libs.accompanist.insets)
|
||||
implementation(libs.accompanist.systemuicontroller)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.activity.ktx)
|
||||
implementation(libs.androidx.autofill)
|
||||
implementation(libs.androidx.collection.ktx)
|
||||
implementation(libs.androidx.compose.material)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.runtime.livedata)
|
||||
implementation(libs.androidx.compose.ui)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
@@ -207,18 +221,23 @@ dependencies {
|
||||
implementation(libs.androidx.core.splashscreen)
|
||||
implementation(libs.androidx.emoji2)
|
||||
implementation(libs.androidx.emoji2.views)
|
||||
implementation(libs.androidx.exifinterface)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
implementation(libs.androidx.profileinstaller)
|
||||
ksp(libs.androidx.room.compiler)
|
||||
implementation(libs.androidx.room.runtime)
|
||||
implementation(libs.cache4k)
|
||||
implementation(libs.jetpref.datastore.model)
|
||||
implementation(libs.jetpref.datastore.ui)
|
||||
implementation(libs.jetpref.material.ui)
|
||||
implementation(libs.kotlinx.coroutines)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.mikepenz.aboutlibraries.core)
|
||||
implementation(libs.mikepenz.aboutlibraries.compose)
|
||||
implementation(libs.patrickgold.compose.tooltip)
|
||||
implementation(libs.patrickgold.jetpref.datastore.model)
|
||||
implementation(libs.patrickgold.jetpref.datastore.ui)
|
||||
implementation(libs.patrickgold.jetpref.material.ui)
|
||||
|
||||
|
||||
implementation(project(":lib:kotlin"))
|
||||
|
||||
testImplementation(libs.equalsverifier)
|
||||
testImplementation(libs.kotest.assertions.core)
|
||||
|
||||
3
app/lint.xml
Normal file
3
app/lint.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<lint>
|
||||
<issue id="UsingMaterialAndMaterial3Libraries" severity="ignore" />
|
||||
</lint>
|
||||
@@ -19,6 +19,9 @@
|
||||
<!-- Permission needed to vibrate if the user has key press vibration enabled -->
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
<!-- Permission needed to create notifications on devices running Android 13+ -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<!-- Android 11+ only: Define that FlorisBoard requests to see all apps that
|
||||
ship with an IME or Spell Check service. This is used to guide the user
|
||||
in the Settings Ui why FlorisBoard may not be working.
|
||||
@@ -80,7 +83,7 @@
|
||||
android:launchMode="singleTask"
|
||||
android:roundIcon="@mipmap/floris_app_icon_round"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:theme="@style/FlorisAppTheme"
|
||||
android:theme="@style/FlorisAppTheme.Splash"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<data android:scheme="florisboard" android:host="app-ui"/>
|
||||
@@ -95,7 +98,7 @@
|
||||
android:launchMode="singleTask"
|
||||
android:roundIcon="@mipmap/floris_app_icon_round"
|
||||
android:targetActivity="dev.patrickgold.florisboard.app.FlorisAppActivity"
|
||||
android:theme="@style/FlorisAppTheme"
|
||||
android:theme="@style/FlorisAppTheme.Splash"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
@@ -128,6 +131,18 @@
|
||||
android:label="@string/crash_dialog__title"
|
||||
android:theme="@style/CrashDialogTheme"/>
|
||||
|
||||
<!-- Copy to Clipboard Activity -->
|
||||
<activity
|
||||
android:name="dev.patrickgold.florisboard.FlorisCopyToClipboardActivity"
|
||||
android:theme="@style/FlorisAppTheme.Transparent"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="image/*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Clipboard Media File Provider -->
|
||||
<provider
|
||||
android:name="dev.patrickgold.florisboard.ime.clipboard.provider.ClipboardMediaProvider"
|
||||
|
||||
Binary file not shown.
@@ -32,6 +32,18 @@
|
||||
{ "code": 163, "label": "£" },
|
||||
{ "code": 165, "label": "¥" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "bangladeshi_taka",
|
||||
"label": "Bangladeshi taka (৳)",
|
||||
"slots": [
|
||||
{ "code": 2547, "label": "৳" },
|
||||
{ "code": 36, "label": "$" },
|
||||
{ "code": 8364, "label": "€" },
|
||||
{ "code": 162, "label": "¢" },
|
||||
{ "code": 163, "label": "£" },
|
||||
{ "code": 165, "label": "¥" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "bitcoin",
|
||||
@@ -45,6 +57,18 @@
|
||||
{ "code": 165, "label": "¥" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "costa_rican_colon",
|
||||
"label": "Costa Rican colón (₡)",
|
||||
"slots": [
|
||||
{ "code": 8353, "label": "₡" },
|
||||
{ "code": 36, "label": "$" },
|
||||
{ "code": 8364, "label": "€" },
|
||||
{ "code": 162, "label": "¢" },
|
||||
{ "code": 163, "label": "£" },
|
||||
{ "code": 165, "label": "¥" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "dollar",
|
||||
"label": "Dollar ($)",
|
||||
|
||||
@@ -42,6 +42,12 @@
|
||||
"label": "AZERTY",
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "bengali_bd",
|
||||
"label": "বাংলা",
|
||||
"authors": [ "iamrasel" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "bepo",
|
||||
@@ -111,6 +117,13 @@
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:dvorak"
|
||||
},
|
||||
{
|
||||
"id": "dvorak_de",
|
||||
"label": "Dvorak (DE)",
|
||||
"authors": [ "msrd0" ],
|
||||
"direction": "ltr",
|
||||
"modifier": "org.florisboard.layouts:dvorak_de"
|
||||
},
|
||||
{
|
||||
"id": "dvorak_es",
|
||||
"label": "Dvorak (ÑÇ)",
|
||||
@@ -130,6 +143,12 @@
|
||||
"authors": [ "jeremiah-miller", "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "estonian",
|
||||
"label": "Estonian",
|
||||
"authors": [ "OneSheepy" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "faroese",
|
||||
"label": "Faroese (QWERTY)",
|
||||
@@ -199,13 +218,13 @@
|
||||
},
|
||||
{
|
||||
"id": "jcuken_russian",
|
||||
"label": "Russian (JCUKEN)",
|
||||
"label": "Russian (ЙЦУКЕН)",
|
||||
"authors": [ "williamtheaker" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "jcuken_ukrainian",
|
||||
"label": "Ukrainian (JCUKEN)",
|
||||
"label": "Ukrainian (ЙЦУКЕН)",
|
||||
"authors": [ "williamtheaker", "33kk" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
@@ -324,6 +343,12 @@
|
||||
"authors": ["GrbavaCigla"],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "slovenian",
|
||||
"label": "Slovenian (QWERTZ)",
|
||||
"authors": ["samo_lego"],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "spanish",
|
||||
"label": "Spanish (QWERTY)",
|
||||
@@ -378,6 +403,18 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "udmurt_compact",
|
||||
"label": "Udmurt (3 чур)",
|
||||
"authors": [ "vorgoron" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "udmurt_extended",
|
||||
"label": "Udmurt (4 чур)",
|
||||
"authors": [ "vorgoron" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "urdu_phonetic",
|
||||
"label": "Urdu Phonetic",
|
||||
@@ -423,6 +460,12 @@
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "dvorak_de",
|
||||
"label": "Dvorak (DE)",
|
||||
"authors": [ "msrd0" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "hebrew",
|
||||
"label": "עברית",
|
||||
@@ -500,6 +543,12 @@
|
||||
"label": "Western Arabic (PC)",
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "bengali",
|
||||
"label": "Bengali",
|
||||
"authors": [ "iamrasel" ],
|
||||
"direction": "ltr"
|
||||
}
|
||||
],
|
||||
"numericRow": [
|
||||
@@ -572,7 +621,7 @@
|
||||
{
|
||||
"id": "tamil",
|
||||
"label": "Tamil",
|
||||
"authors": [ "yashpalgoyal1304" ],
|
||||
"authors": [ "Clem0908" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
@@ -667,6 +716,12 @@
|
||||
"label": "Western (Additional symbols)",
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "western_samsung",
|
||||
"label": "Western (Samsung)",
|
||||
"authors": [ "nettnikl" ],
|
||||
"direction": "ltr"
|
||||
}
|
||||
],
|
||||
"symbolsMod": [
|
||||
@@ -726,6 +781,12 @@
|
||||
"label": "Western",
|
||||
"authors": [ "patrickgold" ],
|
||||
"direction": "ltr"
|
||||
},
|
||||
{
|
||||
"id": "western_samsung",
|
||||
"label": "Western (Samsung)",
|
||||
"authors": [ "nettnikl" ],
|
||||
"direction": "ltr"
|
||||
}
|
||||
],
|
||||
"symbols2Mod": [
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
[
|
||||
[
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2457, "label": "ঙ" },
|
||||
"upper": { "code": 2434, "label": "ং" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2479, "label": "য" },
|
||||
"upper": { "code": 2527, "label": "য়" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2465, "label": "ড" },
|
||||
"upper": { "code": 2466, "label": "ঢ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2474, "label": "প" },
|
||||
"upper": { "code": 2475, "label": "ফ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2463, "label": "ট" },
|
||||
"upper": { "code": 2464, "label": "ঠ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2458, "label": "চ" },
|
||||
"upper": { "code": 2459, "label": "ছ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2460, "label": "জ" },
|
||||
"upper": { "code": 2461, "label": "ঝ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2489, "label": "হ" },
|
||||
"upper": { "code": 2462, "label": "ঞ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2455, "label": "গ" },
|
||||
"upper": { "code": 2456, "label": "ঘ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2524, "label": "ড়" },
|
||||
"upper": { "code": 2525, "label": "ঢ়" }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2499, "label": "ৃ" },
|
||||
"upper": { "$": "multi_text_key", "codePoints": [2480, 2509], "label": "র্" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2497, "label": "ু" },
|
||||
"upper": { "code": 2498, "label": "ূ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2495, "label": "ি" },
|
||||
"upper": { "code": 2496, "label": "ী" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2494, "label": "া" },
|
||||
"upper": { "code": 2437, "label": "অ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2509, "label": "্" },
|
||||
"upper": { "code": 2433, "label": "ঁ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2476, "label": "ব" },
|
||||
"upper": { "code": 2477, "label": "ভ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2453, "label": "ক" },
|
||||
"upper": { "code": 2454, "label": "খ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2468, "label": "ত" },
|
||||
"upper": { "code": 2469, "label": "থ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2470, "label": "দ" },
|
||||
"upper": { "code": 2471, "label": "ধ" }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "case_selector",
|
||||
"lower": { "$": "multi_text_key", "codePoints": [2509, 2480], "label": "্র" },
|
||||
"upper": { "$": "multi_text_key", "codePoints": [2509, 2479], "label": "্য" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2507, "label": "ো" },
|
||||
"upper": { "code": 2508, "label": "ৌ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2503, "label": "ে" },
|
||||
"upper": { "code": 2504, "label": "ৈ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2480, "label": "র" },
|
||||
"upper": { "code": 2482, "label": "ল" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2472, "label": "ন" },
|
||||
"upper": { "code": 2467, "label": "ণ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2488, "label": "স" },
|
||||
"upper": { "code": 2487, "label": "ষ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2478, "label": "ম" },
|
||||
"upper": { "code": 2486, "label": "শ" }
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,71 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 59, "label": ";", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 44, "label": "," }
|
||||
]
|
||||
} },
|
||||
"default": { "code": 44, "label": ",", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 59, "label": ";" }
|
||||
]
|
||||
} }
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 58, "label": ":", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 46, "label": "." }
|
||||
]
|
||||
} },
|
||||
"default": { "code": 46, "label": ".", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 58, "label": ":" }
|
||||
]
|
||||
} }
|
||||
},
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 223, "label": "ß", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
} },
|
||||
"default": { "code": 63, "label": "?", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 223, "label": "ß" }
|
||||
]
|
||||
} }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,38 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 228, "label": "ä" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" },
|
||||
{ "$": "auto_text_key", "code": 245, "label": "õ" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 113, "label": "q" },
|
||||
{ "$": "auto_text_key", "code": 119, "label": "w" },
|
||||
{ "$": "auto_text_key", "code": 101, "label": "e" },
|
||||
{ "$": "auto_text_key", "code": 114, "label": "r" },
|
||||
{ "$": "auto_text_key", "code": 116, "label": "t" },
|
||||
{ "$": "auto_text_key", "code": 122, "label": "z" },
|
||||
{ "$": "auto_text_key", "code": 117, "label": "u" },
|
||||
{ "$": "auto_text_key", "code": 105, "label": "i" },
|
||||
{ "$": "auto_text_key", "code": 111, "label": "o" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" },
|
||||
{ "$": "auto_text_key", "code": 353, "label": "š" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 97, "label": "a" },
|
||||
{ "$": "auto_text_key", "code": 115, "label": "s" },
|
||||
{ "$": "auto_text_key", "code": 100, "label": "d" },
|
||||
{ "$": "auto_text_key", "code": 102, "label": "f" },
|
||||
{ "$": "auto_text_key", "code": 103, "label": "g" },
|
||||
{ "$": "auto_text_key", "code": 104, "label": "h" },
|
||||
{ "$": "auto_text_key", "code": 106, "label": "j" },
|
||||
{ "$": "auto_text_key", "code": 107, "label": "k" },
|
||||
{ "$": "auto_text_key", "code": 108, "label": "l" },
|
||||
{ "$": "auto_text_key", "code": 269, "label": "č" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 121, "label": "y" },
|
||||
{ "$": "auto_text_key", "code": 120, "label": "x" },
|
||||
{ "$": "auto_text_key", "code": 99, "label": "c" },
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 98, "label": "b" },
|
||||
{ "$": "auto_text_key", "code": 110, "label": "n" },
|
||||
{ "$": "auto_text_key", "code": 109, "label": "m" },
|
||||
{ "$": "auto_text_key", "code": 382, "label": "ž" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,98 @@
|
||||
[
|
||||
[
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2974, "label": "ஞ" },
|
||||
"upper": { "code": 2998, "label": "ஶ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2993, "label": "ற" },
|
||||
"upper": { "code": 2999, "label": "ஷ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2984, "label": "ந" },
|
||||
"upper": { "code": 3000, "label": "ஸ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2970, "label": "ச" },
|
||||
"upper": { "code": 3001, "label": "ஹ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2997, "label": "வ" },
|
||||
"upper": { "code": 2972, "label": "ஜ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2992, "label": "ர" },
|
||||
"upper": { "code": 2994, "label": "ல" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3016, "label": "ை" },
|
||||
"upper": { "code": 2960, "label": "ஐ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3018, "label": "ொ" },
|
||||
"upper": { "code": 3019, "label": "ோ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3007, "label": "ி" },
|
||||
"upper": { "code": 3008, "label": "ீ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3009, "label": "ு" },
|
||||
"upper": { "code": 3010, "label": "ூ" }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 2991, "label": "ய" },
|
||||
{ "$": "auto_text_key", "code": 2995, "label": "ள" },
|
||||
{ "$": "auto_text_key", "code": 2985, "label": "ன" },
|
||||
{ "$": "auto_text_key", "code": 2965, "label": "க" },
|
||||
{ "$": "auto_text_key", "code": 2986, "label": "ப" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3006, "label": "ா" },
|
||||
"upper": { "code": 2996, "label": "ழ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2980, "label": "த" },
|
||||
"upper": { "code": 2990, "label": "ம" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2975, "label": "ட" },
|
||||
"upper": { "code": 2969, "label": "ங" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3021, "label": "்" },
|
||||
"upper": { "code": 2947, "label": "ஃ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2951, "label": "இ" },
|
||||
"upper": { "code": 2952, "label": "ஈ" }
|
||||
}
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 2979, "label": "ண" },
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2962, "label": "ஒ" },
|
||||
"upper": { "code": 2963, "label": "ஓ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2953, "label": "உ" },
|
||||
"upper": { "code": 2954, "label": "ஊ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2958, "label": "எ" },
|
||||
"upper": { "code": 2959, "label": "ஏ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 3014, "label": "ெ" },
|
||||
"upper": { "code": 3015, "label": "ே" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2964, "label": "ஔ" },
|
||||
"upper": { "code": 3020, "label": "ௌ" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 2949, "label": "அ" },
|
||||
"upper": { "code": 2950, "label": "ஆ" }
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,59 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1081, "label": "й" },
|
||||
{ "$": "auto_text_key", "code": 1094, "label": "ц" },
|
||||
{ "$": "auto_text_key", "code": 1091, "label": "у" },
|
||||
{ "$": "auto_text_key", "code": 1082, "label": "к" },
|
||||
{ "$": "auto_text_key", "code": 1077, "label": "е" },
|
||||
{ "$": "auto_text_key", "code": 1085, "label": "н" },
|
||||
{ "$": "auto_text_key", "code": 1075, "label": "г" },
|
||||
{ "$": "auto_text_key", "code": 1096, "label": "ш" },
|
||||
{ "$": "auto_text_key", "code": 1097, "label": "щ" },
|
||||
{ "code": 1079, "label": "з", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1247, "label": "ӟ" }
|
||||
]
|
||||
} },
|
||||
{ "$": "auto_text_key", "code": 1093, "label": "х" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1092 , "label": "ф" },
|
||||
{ "$": "auto_text_key", "code": 1099 , "label": "ы" },
|
||||
{ "$": "auto_text_key", "code": 1074 , "label": "в" },
|
||||
{ "$": "auto_text_key", "code": 1072 , "label": "а" },
|
||||
{ "$": "auto_text_key", "code": 1087 , "label": "п" },
|
||||
{ "$": "auto_text_key", "code": 1088 , "label": "р" },
|
||||
{ "$": "auto_text_key", "code": 1086 , "label": "о", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1255, "label": "ӧ" }
|
||||
]
|
||||
} },
|
||||
{ "$": "auto_text_key", "code": 1083 , "label": "л" },
|
||||
{ "$": "auto_text_key", "code": 1076 , "label": "д" },
|
||||
{ "$": "auto_text_key", "code": 1078 , "label": "ж", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1245, "label": "ӝ" }
|
||||
]
|
||||
} },
|
||||
{ "$": "auto_text_key", "code": 1101 , "label": "э" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1103 , "label": "я" },
|
||||
{ "$": "auto_text_key", "code": 1095 , "label": "ч", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1269, "label": "ӵ" }
|
||||
]
|
||||
} },
|
||||
{ "$": "auto_text_key", "code": 1089 , "label": "с" },
|
||||
{ "$": "auto_text_key", "code": 1084 , "label": "м" },
|
||||
{ "$": "auto_text_key", "code": 1080 , "label": "и", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 1253, "label": "ӥ" }
|
||||
]
|
||||
} },
|
||||
{ "$": "auto_text_key", "code": 1090 , "label": "т" },
|
||||
{ "$": "auto_text_key", "code": 1100 , "label": "ь" },
|
||||
{ "$": "auto_text_key", "code": 1073 , "label": "б" },
|
||||
{ "$": "auto_text_key", "code": 1102 , "label": "ю" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,48 @@
|
||||
[
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1081, "label": "ё" },
|
||||
{ "$": "auto_text_key", "code": 1245, "label": "ӝ" },
|
||||
{ "$": "auto_text_key", "code": 1255, "label": "ӧ" },
|
||||
{ "$": "auto_text_key", "code": 1269, "label": "ӵ" },
|
||||
{ "$": "auto_text_key", "code": 1253, "label": "ӥ" },
|
||||
{ "$": "auto_text_key", "code": 1247, "label": "ӟ" },
|
||||
{ "$": "auto_text_key", "code": 1100, "label": "ь" },
|
||||
{ "$": "auto_text_key", "code": 1098, "label": "ъ" },
|
||||
{ "$": "auto_text_key", "code": 1093, "label": "х" },
|
||||
{ "$": "auto_text_key", "code": 1101, "label": "э" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1081, "label": "й" },
|
||||
{ "$": "auto_text_key", "code": 1094, "label": "ц" },
|
||||
{ "$": "auto_text_key", "code": 1091, "label": "у" },
|
||||
{ "$": "auto_text_key", "code": 1082, "label": "к" },
|
||||
{ "$": "auto_text_key", "code": 1077, "label": "е" },
|
||||
{ "$": "auto_text_key", "code": 1085, "label": "н" },
|
||||
{ "$": "auto_text_key", "code": 1075, "label": "г" },
|
||||
{ "$": "auto_text_key", "code": 1096, "label": "ш" },
|
||||
{ "$": "auto_text_key", "code": 1097, "label": "щ" },
|
||||
{ "$": "auto_text_key", "code": 1079, "label": "з" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1092 , "label": "ф" },
|
||||
{ "$": "auto_text_key", "code": 1099 , "label": "ы" },
|
||||
{ "$": "auto_text_key", "code": 1074 , "label": "в" },
|
||||
{ "$": "auto_text_key", "code": 1072 , "label": "а" },
|
||||
{ "$": "auto_text_key", "code": 1087 , "label": "п" },
|
||||
{ "$": "auto_text_key", "code": 1088 , "label": "р" },
|
||||
{ "$": "auto_text_key", "code": 1086 , "label": "о" },
|
||||
{ "$": "auto_text_key", "code": 1083 , "label": "л" },
|
||||
{ "$": "auto_text_key", "code": 1076 , "label": "д" },
|
||||
{ "$": "auto_text_key", "code": 1078 , "label": "ж" }
|
||||
],
|
||||
[
|
||||
{ "$": "auto_text_key", "code": 1103 , "label": "я" },
|
||||
{ "$": "auto_text_key", "code": 1095 , "label": "ч" },
|
||||
{ "$": "auto_text_key", "code": 1089 , "label": "с" },
|
||||
{ "$": "auto_text_key", "code": 1084 , "label": "м" },
|
||||
{ "$": "auto_text_key", "code": 1080 , "label": "и" },
|
||||
{ "$": "auto_text_key", "code": 1090 , "label": "т" },
|
||||
{ "$": "auto_text_key", "code": 1073 , "label": "б" },
|
||||
{ "$": "auto_text_key", "code": 1102 , "label": "ю" }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,16 @@
|
||||
[
|
||||
[
|
||||
{ "code": -11, "label": "shift", "type": "modifier" },
|
||||
{ "code": 0, "type": "placeholder" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "$": "auto_text_key", "code": 228, "label": "ä", "groupId": 1 },
|
||||
{ "code": -227, "label": "language_switch", "type": "system_gui" },
|
||||
{ "code": -212, "label": "ime_ui_mode_media", "type": "system_gui" },
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -14,7 +14,6 @@
|
||||
{ "code": -212, "label": "ime_ui_mode_media", "type": "system_gui" },
|
||||
{ "code": 32, "label": "space" },
|
||||
{ "code": 8204, "label": "half_space" },
|
||||
{ "code": 1600, "label": "kashida" },
|
||||
{ "code": 46, "label": ".", "groupId": 2 },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
[
|
||||
[
|
||||
{ "code": -35, "label": "clipboard_select_all", "type": "enter_editing" },
|
||||
{ "code": -31, "label": "clipboard_copy", "type": "enter_editing" },
|
||||
{ "code": -32, "label": "clipboard_cut", "type": "enter_editing" },
|
||||
{ "code": -21, "label": "arrow_left", "type": "navigation" },
|
||||
{ "code": -22, "label": "arrow_right", "type": "navigation" },
|
||||
{ "code": -33, "label": "clipboard_paste", "type": "enter_editing" },
|
||||
{ "code": -38, "label": "clipboard_clear_primary_clip", "type": "system_gui"},
|
||||
{ "code": -213, "label": "ime_ui_mode_clipboard", "type": "system_gui"}
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,48 @@
|
||||
[
|
||||
[
|
||||
{ "code": 43, "label": "+", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 215, "label": "×" },
|
||||
{ "code": 247, "label": "÷" }
|
||||
]
|
||||
} },
|
||||
{ "code": 2535, "label": "১", "type": "numeric" },
|
||||
{ "code": 2536, "label": "২", "type": "numeric" },
|
||||
{ "code": 2537, "label": "৩", "type": "numeric" },
|
||||
{ "code": 37, "label": "%" }
|
||||
],
|
||||
[
|
||||
{ "code": 40, "label": "(", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 91, "label": "[" },
|
||||
{ "code": 123, "label": "{" }
|
||||
]
|
||||
} },
|
||||
{ "code": 2538, "label": "৪", "type": "numeric" },
|
||||
{ "code": 2539, "label": "৫", "type": "numeric" },
|
||||
{ "code": 2540, "label": "৬", "type": "numeric" },
|
||||
{ "code": 32, "label": "space" }
|
||||
],
|
||||
[
|
||||
{ "code": 41, "label": ")", "popup": {
|
||||
"relevant": [
|
||||
{ "code": 93, "label": "]" },
|
||||
{ "code": 125, "label": "}" }
|
||||
]
|
||||
} },
|
||||
{ "code": 2541, "label": "৭", "type": "numeric" },
|
||||
{ "code": 2542, "label": "৮", "type": "numeric" },
|
||||
{ "code": 2543, "label": "৯", "type": "numeric" },
|
||||
{ "code": -7, "label": "delete", "type": "enter_editing" }
|
||||
],
|
||||
[
|
||||
{ "code": -201, "label": "view_characters", "type": "system_gui" },
|
||||
{ "code": 44, "label": "," },
|
||||
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
|
||||
{ "code": 2534, "label": "০", "type": "numeric" },
|
||||
{ "code": 61, "label": "=" },
|
||||
{ "code": 46, "label": "." },
|
||||
{ "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" }
|
||||
]
|
||||
]
|
||||
@@ -54,7 +54,7 @@
|
||||
{ "code": 3672, "label": "๘", "type": "numeric", "popup": {
|
||||
"main": { "code": 8312, "label": "⁸" }
|
||||
} },
|
||||
{ "code": 3672, "label": "๘", "type": "numeric", "popup": {
|
||||
{ "code": 3673, "label": "๙", "type": "numeric", "popup": {
|
||||
"main": { "code": 8313, "label": "⁹" }
|
||||
} },
|
||||
{ "code": 3664, "label": "๐", "type": "numeric", "popup": {
|
||||
|
||||
@@ -1,68 +1,200 @@
|
||||
[
|
||||
[
|
||||
{ "code": 49, "label": "1", "type": "numeric", "popup": {
|
||||
"main": { "code": 185, "label": "¹" },
|
||||
"relevant": [
|
||||
{ "code": 8537, "label": "⅙" },
|
||||
{ "code": 8528, "label": "⅐" },
|
||||
{ "code": 8539, "label": "⅛" },
|
||||
{ "code": 8529, "label": "⅑" },
|
||||
{ "code": 8530, "label": "⅒" },
|
||||
{ "code": 189, "label": "½" },
|
||||
{ "code": 8531, "label": "⅓" },
|
||||
{ "code": 188, "label": "¼" },
|
||||
{ "code": 8533, "label": "⅕" }
|
||||
]
|
||||
} },
|
||||
{ "code": 50, "label": "2", "type": "numeric", "popup": {
|
||||
"main": { "code": 178, "label": "²" },
|
||||
"relevant": [
|
||||
{ "code": 8532, "label": "⅔" },
|
||||
{ "code": 8534, "label": "⅖" }
|
||||
]
|
||||
} },
|
||||
{ "code": 51, "label": "3", "type": "numeric", "popup": {
|
||||
"main": { "code": 179, "label": "³" },
|
||||
"relevant": [
|
||||
{ "code": 8535, "label": "⅗" },
|
||||
{ "code": 190, "label": "¾" },
|
||||
{ "code": 8540, "label": "⅜" }
|
||||
]
|
||||
} },
|
||||
{ "code": 52, "label": "4", "type": "numeric", "popup": {
|
||||
"main": { "code": 8308, "label": "⁴" },
|
||||
"relevant": [
|
||||
{ "code": 8536, "label": "⅘" }
|
||||
]
|
||||
} },
|
||||
{ "code": 53, "label": "5", "type": "numeric", "popup": {
|
||||
"main": { "code": 8309, "label": "⁵" },
|
||||
"relevant": [
|
||||
{ "code": 8538, "label": "⅚" },
|
||||
{ "code": 8541, "label": "⅝" }
|
||||
]
|
||||
} },
|
||||
{ "code": 54, "label": "6", "type": "numeric", "popup": {
|
||||
"main": { "code": 8310, "label": "⁶" }
|
||||
} },
|
||||
{ "code": 55, "label": "7", "type": "numeric", "popup": {
|
||||
"main": { "code": 8311, "label": "⁷" },
|
||||
"relevant": [
|
||||
{ "code": 8542, "label": "⅞" }
|
||||
]
|
||||
} },
|
||||
{ "code": 56, "label": "8", "type": "numeric", "popup": {
|
||||
"main": { "code": 8312, "label": "⁸" }
|
||||
} },
|
||||
{ "code": 57, "label": "9", "type": "numeric", "popup": {
|
||||
"main": { "code": 8313, "label": "⁹" }
|
||||
} },
|
||||
{ "code": 48, "label": "0", "type": "numeric", "popup": {
|
||||
"main": { "code": 8304, "label": "⁰" },
|
||||
"relevant": [
|
||||
{ "code": 8709, "label": "∅" },
|
||||
{ "code": 8319, "label": "ⁿ" }
|
||||
]
|
||||
} }
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"code": 33, "label": "!", "type": "numeric", "popup": {
|
||||
"main": { "code": 161, "label": "¡" }
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 49, "label": "1", "type": "numeric", "popup": {
|
||||
"main": { "code": 185, "label": "¹" },
|
||||
"relevant": [
|
||||
{ "code": 8537, "label": "⅙" },
|
||||
{ "code": 8528, "label": "⅐" },
|
||||
{ "code": 8539, "label": "⅛" },
|
||||
{ "code": 8529, "label": "⅑" },
|
||||
{ "code": 8530, "label": "⅒" },
|
||||
{ "code": 189, "label": "½" },
|
||||
{ "code": 8531, "label": "⅓" },
|
||||
{ "code": 188, "label": "¼" },
|
||||
{ "code": 8533, "label": "⅕" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 64, "label": "@", "type": "numeric" },
|
||||
"default": {
|
||||
"code": 50, "label": "2", "type": "numeric", "popup": {
|
||||
"main": { "code": 178, "label": "²" },
|
||||
"relevant": [
|
||||
{ "code": 8532, "label": "⅔" },
|
||||
{ "code": 8534, "label": "⅖" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"code": 35, "label": "#", "type": "numeric", "popup": {
|
||||
"main": { "code": 8470, "label": "№" }
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 51, "label": "3", "type": "numeric", "popup": {
|
||||
"main": { "code": 179, "label": "³" },
|
||||
"relevant": [
|
||||
{ "code": 8535, "label": "⅗" },
|
||||
{ "code": 190, "label": "¾" },
|
||||
{ "code": 8540, "label": "⅜" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"code": -801, "label": "currency_slot_1", "type": "numeric", "popup": {
|
||||
"main": { "code": -802, "label": "currency_slot_2" },
|
||||
"relevant": [
|
||||
{ "code": -806, "label": "currency_slot_6" },
|
||||
{ "code": -803, "label": "currency_slot_3" },
|
||||
{ "code": -804, "label": "currency_slot_4" },
|
||||
{ "code": -805, "label": "currency_slot_5" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 52, "label": "4", "type": "numeric", "popup": {
|
||||
"main": { "code": 8308, "label": "⁴" },
|
||||
"relevant": [
|
||||
{ "code": 8536, "label": "⅘" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"code": 37, "label": "%", "type": "numeric", "popup": {
|
||||
"main": { "code": 8240, "label": "‰" },
|
||||
"relevant": [
|
||||
{ "code": 8453, "label": "℅" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 53, "label": "5", "type": "numeric", "popup": {
|
||||
"main": { "code": 8309, "label": "⁵" },
|
||||
"relevant": [
|
||||
{ "code": 8538, "label": "⅚" },
|
||||
{ "code": 8541, "label": "⅝" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"code": 94, "label": "^", "type": "numeric", "popup": {
|
||||
"main": { "code": 8593, "label": "↑" },
|
||||
"relevant": [
|
||||
{ "code": 8592, "label": "←" },
|
||||
{ "code": 8595, "label": "↓" },
|
||||
{ "code": 8594, "label": "→" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 54, "label": "6", "type": "numeric", "popup": {
|
||||
"main": { "code": 8310, "label": "⁶" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": { "code": 38, "label": "&", "type": "numeric" },
|
||||
"default": {
|
||||
"code": 55, "label": "7", "type": "numeric", "popup": {
|
||||
"main": { "code": 8311, "label": "⁷" },
|
||||
"relevant": [
|
||||
{ "code": 8542, "label": "⅞" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"code": 42, "label": "*", "type": "numeric", "popup": {
|
||||
"main": { "code": 8224, "label": "†" },
|
||||
"relevant": [
|
||||
{ "code": 9733, "label": "★" },
|
||||
{ "code": 8225, "label": "‡" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 56, "label": "8", "type": "numeric", "popup": {
|
||||
"main": { "code": 8312, "label": "⁸" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"$": "layout_direction_selector",
|
||||
"ltr": {
|
||||
"code": 40, "label": "(", "type": "numeric", "popup": {
|
||||
"main": { "code": 60, "label": "<" },
|
||||
"relevant": [
|
||||
{ "code": 91, "label": "[" },
|
||||
{ "code": 123, "label": "{" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"rtl": {
|
||||
"code": 41, "label": "(", "type": "numeric", "popup": {
|
||||
"main": { "code": 62, "label": "<" },
|
||||
"relevant": [
|
||||
{ "code": 93, "label": "[" },
|
||||
{ "code": 125, "label": "{" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 57, "label": "9", "type": "numeric", "popup": {
|
||||
"main": { "code": 8313, "label": "⁹" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "$": "shift_state_selector",
|
||||
"shiftedManual": {
|
||||
"$": "layout_direction_selector",
|
||||
"ltr": {
|
||||
"code": 41, "label": ")", "type": "numeric", "popup": {
|
||||
"main": { "code": 62, "label": ">" },
|
||||
"relevant": [
|
||||
{ "code": 93, "label": "]" },
|
||||
{ "code": 125, "label": "}" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"rtl": {
|
||||
"code": 40, "label": ")", "type": "numeric", "popup": {
|
||||
"main": { "code": 60, "label": ">" },
|
||||
"relevant": [
|
||||
{ "code": 91, "label": "]" },
|
||||
{ "code": 123, "label": "}" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"code": 48, "label": "0", "type": "numeric", "popup": {
|
||||
"main": { "code": 8304, "label": "⁰" },
|
||||
"relevant": [
|
||||
{ "code": 8709, "label": "∅" },
|
||||
{ "code": 8319, "label": "ⁿ" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
[
|
||||
[
|
||||
{ "code": 43, "label": "+", "popup": {
|
||||
"main": { "code": 177, "label": "±" }
|
||||
} },
|
||||
{ "code": 215, "label": "×" },
|
||||
{ "code": 247, "label": "÷" },
|
||||
{ "code": 61, "label": "=", "popup": {
|
||||
"main": { "code": 8776, "label": "≈" },
|
||||
"relevant": [
|
||||
{ "code": 8800, "label": "≠" },
|
||||
{ "code": 8801, "label": "≡" }
|
||||
]
|
||||
} },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "code": 95, "label": "_" },
|
||||
{ "code": 60, "label": "<" },
|
||||
{ "code": 62, "label": ">" },
|
||||
{ "code": 91, "label": "[", "popup": {
|
||||
"main": { "code": 12302, "label": "『" },
|
||||
"relevant": [
|
||||
{ "code": 12300, "label": "「" },
|
||||
{ "code": 12308, "label": "〔" },
|
||||
{ "code": 12304, "label": "【" }
|
||||
]
|
||||
} },
|
||||
{ "code": 93, "label": "]", "popup": {
|
||||
"main": { "code": 12303, "label": "』" },
|
||||
"relevant": [
|
||||
{ "code": 12301, "label": "」" },
|
||||
{ "code": 12309, "label": "〕" },
|
||||
{ "code": 12305, "label": "】" }
|
||||
]
|
||||
} }
|
||||
],
|
||||
[
|
||||
{ "code": 33, "label": "!", "popup": {
|
||||
"main": { "code": 161, "label": "¡" }
|
||||
} },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 35, "label": "#", "popup": {
|
||||
"main": { "code": 8470, "label": "№" }
|
||||
} },
|
||||
{ "code": -801, "label": "currency_slot_1", "popup": {
|
||||
"main": { "code": -802, "label": "currency_slot_2" },
|
||||
"relevant": [
|
||||
{ "code": -806, "label": "currency_slot_6" },
|
||||
{ "code": -803, "label": "currency_slot_3" },
|
||||
{ "code": -804, "label": "currency_slot_4" },
|
||||
{ "code": -805, "label": "currency_slot_5" }
|
||||
]
|
||||
} },
|
||||
{ "code": 37, "label": "%", "popup": {
|
||||
"main": { "code": 1642, "label": "٪" },
|
||||
"relevant": [
|
||||
{ "code": 8240, "label": "‰" }
|
||||
]
|
||||
} },
|
||||
{ "code": 94, "label": "^" },
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 42, "label": "*" },
|
||||
{ "code": 40, "label": "(" },
|
||||
{ "code": 41, "label": ")" }
|
||||
],
|
||||
[
|
||||
{ "code": 45, "label": "-", "popup": {
|
||||
"main": { "code": 8208, "label": "‐" },
|
||||
"relevant": [
|
||||
{ "code": 8211, "label": "–" },
|
||||
{ "code": 8212, "label": "—" }
|
||||
]
|
||||
} },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 44, "label": "," },
|
||||
{ "code": 63, "label": "?", "popup": {
|
||||
"main": { "code": 191, "label": "¿" },
|
||||
"relevant": [
|
||||
{ "code": 8253, "label": "‽" }
|
||||
]
|
||||
} }
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
[
|
||||
[
|
||||
{ "code": 96, "label": "`" },
|
||||
{ "code": 126, "label": "~" },
|
||||
{ "code": 92, "label": "\\" },
|
||||
{ "code": 124, "label": "|" },
|
||||
{ "code": 123, "label": "{" },
|
||||
{ "code": 125, "label": "}" },
|
||||
{ "code": -802, "label": "currency_slot_2" },
|
||||
{ "code": -804, "label": "currency_slot_4" },
|
||||
{ "code": -805, "label": "currency_slot_5" },
|
||||
{ "code": -806, "label": "currency_slot_6" }
|
||||
],
|
||||
[
|
||||
{ "code": 176, "label": "°" },
|
||||
{ "code": 8226, "label": "•" },
|
||||
{ "code": 9675, "label": "○" },
|
||||
{ "code": 9679, "label": "●" },
|
||||
{ "code": 9633, "label": "□" },
|
||||
{ "code": 9632, "label": "■" },
|
||||
{ "code": 9828, "label": "♤", "popup": {
|
||||
"main": { "code": 9824, "label": "♠️" }
|
||||
} },
|
||||
{ "code": 9825, "label": "♡", "popup": {
|
||||
"main": { "code": 9829, "label": "♥️" }
|
||||
} },
|
||||
{ "code": 9671, "label": "◇", "popup": {
|
||||
"main": { "code": 9670, "label": "◆" }
|
||||
} },
|
||||
{ "code": 9831, "label": "♧", "popup": {
|
||||
"main": { "code": 9827, "label": "♣️" }
|
||||
} }
|
||||
],
|
||||
[
|
||||
{ "code": 9734, "label": "☆", "popup": {
|
||||
"main": { "code": 9733, "label": "★" }
|
||||
} },
|
||||
{ "code": 9642, "label": "▪️" },
|
||||
{ "code": 164, "label": "¤" },
|
||||
{ "code":12298, "label": "《" },
|
||||
{ "code":12299, "label": "》" },
|
||||
{ "code": 161, "label": "¡" },
|
||||
{ "code": 191, "label": "¿" }
|
||||
]
|
||||
]
|
||||
@@ -8,7 +8,7 @@
|
||||
{ "code": -201, "label": "view_characters", "type": "system_gui" },
|
||||
{ "$": "char_width_selector",
|
||||
"full": { "code": 12289, "label": "、", "popup": {
|
||||
"main": { "code": 44, "label": "," }
|
||||
"main": { "code": 65292, "label": "," }
|
||||
}
|
||||
},
|
||||
"half": { "code": 65380, "label": "、", "popup": {
|
||||
|
||||
@@ -17,14 +17,19 @@
|
||||
{
|
||||
"id": "default",
|
||||
"label": "Default",
|
||||
"symbolsPrecedingSpace": ".*[.,;:!?‽&%)\\]}»©®™\\p{L}0-9]",
|
||||
"symbolsFollowingSpace": "[\\p{L}0-9].*"
|
||||
"symbolsPrecedingAutoSpace": ".,?‽!\"&%)]}»",
|
||||
"symbolsFollowingAutoSpace": "",
|
||||
"symbolsPrecedingPhantomSpace": ".,;:?‽!&%)]}»©®™",
|
||||
"symbolsFollowingPhantomSpace": "¿⸘¡([{",
|
||||
"symbolsTerminatingSentence": ".?‽!"
|
||||
}
|
||||
],
|
||||
"popupMappings": [
|
||||
{ "id": "default", "authors": [ "patrickgold" ] },
|
||||
{ "id": "ar", "authors": [ "HeiWiper" ] },
|
||||
{ "id": "ast", "authors": [ "Softastur" ] },
|
||||
{ "id": "bg", "authors": [ "iorvethe" ] },
|
||||
{ "id": "bn-BD", "authors": [ "iamrasel" ] },
|
||||
{ "id": "ca", "authors": [ "mikelloc" ] },
|
||||
{ "id": "ckb", "authors": [ "GoRaN" ] },
|
||||
{ "id": "cs", "authors": [ "stefan-misik" ] },
|
||||
@@ -35,6 +40,7 @@
|
||||
{ "id": "en", "authors": [ "patrickgold" ] },
|
||||
{ "id": "eo", "authors": [ "jeremiah-miller" ] },
|
||||
{ "id": "es", "authors": [ "patrickgold" ] },
|
||||
{ "id": "et", "authors": [ "OneSheepy" ] },
|
||||
{ "id": "fa", "authors": [ "PHELAT" ] },
|
||||
{ "id": "fa2", "authors": [ "M-Koushan" ] },
|
||||
{ "id": "fa3", "authors": [ "SaeID-Rz" ] },
|
||||
@@ -49,6 +55,7 @@
|
||||
{ "id": "it", "authors": [ "patrickgold" ] },
|
||||
{ "id": "iw", "authors": [ "Antony" ] },
|
||||
{ "id": "ja-JP-jis", "authors": [ "waelwindows" ] },
|
||||
{ "id": "kab", "authors": [ "yanis867" ] },
|
||||
{ "id": "ko", "authors": [ "patrickgold", "Hayleia" ] },
|
||||
{ "id": "ku", "authors": [ "GoRaN" ] },
|
||||
{ "id": "lt", "authors": [ "patrickgold" ] },
|
||||
@@ -513,6 +520,15 @@
|
||||
"characters": "org.florisboard.layouts:serbian_cyrillic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "sl-SI",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:euro",
|
||||
"popupMapping": "org.florisboard.localization:sl-SI",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:slovenian"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "lv-LV",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -633,6 +649,15 @@
|
||||
"numericRow": "org.florisboard.layouts:warang_citi"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "udm",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:russian_ruble",
|
||||
"popupMapping": "org.florisboard.localization:udm",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:udmurt_extended"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ur-PK",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
@@ -641,6 +666,58 @@
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:urdu_phonetic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "zh-CN-zhengma",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"nlpProviders": {
|
||||
"spelling": "org.florisboard.nlp.providers.han.shape",
|
||||
"suggestion": "org.florisboard.nlp.providers.han.shape"
|
||||
},
|
||||
"currencySet": "org.florisboard.currencysets:yen",
|
||||
"popupMapping": "org.florisboard.localization:en",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:qwerty",
|
||||
"symbols": "org.florisboard.layouts:cjk",
|
||||
"symbols2": "org.florisboard.layouts:cjk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "bn-BD",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:bangladeshi_taka",
|
||||
"popupMapping": "org.florisboard.localization:bn-BD",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:bengali_bd",
|
||||
"numericRow": "org.florisboard.layouts:bengali",
|
||||
"numericAdvanced": "org.florisboard.layouts:bengali"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ast",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:euro",
|
||||
"popupMapping": "org.florisboard.localization:ast",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:qwerty"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "ta-lk",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:indian_rupee",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:tamil"
|
||||
}
|
||||
},
|
||||
{
|
||||
"languageTag": "kab",
|
||||
"composer": "org.florisboard.composers:appender",
|
||||
"currencySet": "org.florisboard.currencysets:euro",
|
||||
"popupMapping": "org.florisboard.localization:kab",
|
||||
"preferred": {
|
||||
"characters": "org.florisboard.layouts:qwerty"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"all": {
|
||||
"a": {
|
||||
"main": { "$": "auto_text_key", "code": 225, "label": "á" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 170, "label": "ª" },
|
||||
{ "$": "auto_text_key", "code": 229, "label": "å" },
|
||||
{ "$": "auto_text_key", "code": 261, "label": "ą" },
|
||||
{ "$": "auto_text_key", "code": 230, "label": "æ" },
|
||||
{ "$": "auto_text_key", "code": 257, "label": "ā" },
|
||||
{ "$": "auto_text_key", "code": 224, "label": "à" },
|
||||
{ "$": "auto_text_key", "code": 228, "label": "ä" },
|
||||
{ "$": "auto_text_key", "code": 226, "label": "â" },
|
||||
{ "$": "auto_text_key", "code": 227, "label": "ã" }
|
||||
]
|
||||
},
|
||||
"c": {
|
||||
"main": { "$": "auto_text_key", "code": 231, "label": "ç" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 269, "label": "č" },
|
||||
{ "$": "auto_text_key", "code": 263, "label": "ć" }
|
||||
]
|
||||
},
|
||||
"e": {
|
||||
"main": { "$": "auto_text_key", "code": 233, "label": "é" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 7497, "label": "ᵉ" },
|
||||
{ "$": "auto_text_key", "code": 275, "label": "ē" },
|
||||
{ "$": "auto_text_key", "code": 281, "label": "ę" },
|
||||
{ "$": "auto_text_key", "code": 279, "label": "ė" },
|
||||
{ "$": "auto_text_key", "code": 235, "label": "ë" },
|
||||
{ "$": "auto_text_key", "code": 232, "label": "è" },
|
||||
{ "$": "auto_text_key", "code": 234, "label": "ê" }
|
||||
]
|
||||
},
|
||||
"h": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 7717, "label": "ḥ" }
|
||||
]
|
||||
},
|
||||
"i": {
|
||||
"main": { "$": "auto_text_key", "code": 237, "label": "í" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 299, "label": "ī" },
|
||||
{ "$": "auto_text_key", "code": 238, "label": "î" },
|
||||
{ "$": "auto_text_key", "code": 303, "label": "į" },
|
||||
{ "$": "auto_text_key", "code": 236, "label": "ì" },
|
||||
{ "$": "auto_text_key", "code": 239, "label": "ï" }
|
||||
]
|
||||
},
|
||||
"l": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 7735, "label": "ḷ" }
|
||||
]
|
||||
},
|
||||
"n": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 241, "label": "ñ" },
|
||||
{ "$": "auto_text_key", "code": 324, "label": "ń" }
|
||||
]
|
||||
},
|
||||
"o": {
|
||||
"main": { "$": "auto_text_key", "code": 243, "label": "ó" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 186, "label": "º" },
|
||||
{ "$": "auto_text_key", "code": 333, "label": "ō" },
|
||||
{ "$": "auto_text_key", "code": 248, "label": "ø" },
|
||||
{ "$": "auto_text_key", "code": 339, "label": "œ" },
|
||||
{ "$": "auto_text_key", "code": 245, "label": "õ" },
|
||||
{ "$": "auto_text_key", "code": 244, "label": "ô" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 242, "label": "ò" }
|
||||
]
|
||||
},
|
||||
"r": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 691, "label": "ʳ" }
|
||||
]
|
||||
},
|
||||
"s": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 223, "label": "ß" }
|
||||
]
|
||||
},
|
||||
"u": {
|
||||
"main": { "$": "auto_text_key", "code": 250, "label": "ú" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 7512, "label": "ᵘ" },
|
||||
{ "$": "auto_text_key", "code": 363, "label": "ū" },
|
||||
{ "$": "auto_text_key", "code": 249, "label": "ù" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
{ "$": "auto_text_key", "code": 251, "label": "û" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 58, "label": ":" },
|
||||
"relevant": [
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 8230, "label": "…" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".es" },
|
||||
{ "code": -255, "label": ".com.es" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"all": {
|
||||
"ঙ": {
|
||||
"main": { "$": "auto_text_key", "code": 2434, "label": "ং" }
|
||||
},
|
||||
"য": {
|
||||
"main": { "$": "auto_text_key", "code": 2527, "label": "য়" }
|
||||
},
|
||||
"ড": {
|
||||
"main": { "$": "auto_text_key", "code": 2466, "label": "ঢ" }
|
||||
},
|
||||
"প": {
|
||||
"main": { "$": "auto_text_key", "code": 2475, "label": "ফ" }
|
||||
},
|
||||
"ট": {
|
||||
"main": { "$": "auto_text_key", "code": 2464, "label": "ঠ" }
|
||||
},
|
||||
"চ": {
|
||||
"main": { "$": "auto_text_key", "code": 2459, "label": "ছ" }
|
||||
},
|
||||
"জ": {
|
||||
"main": { "$": "auto_text_key", "code": 2461, "label": "ঝ" }
|
||||
},
|
||||
"হ": {
|
||||
"main": { "$": "auto_text_key", "code": 2462, "label": "ঞ" }
|
||||
},
|
||||
"গ": {
|
||||
"main": { "$": "auto_text_key", "code": 2456, "label": "ঘ" }
|
||||
},
|
||||
"ড়": {
|
||||
"main": { "$": "auto_text_key", "code": 2525, "label": "ঢ়" }
|
||||
},
|
||||
"ৃ": {
|
||||
"main": { "$": "auto_text_key", "code": 2443, "label": "ঋ" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 2500, "label": "ৄ" },
|
||||
{ "$": "auto_text_key", "code": 2528, "label": "ৠ" },
|
||||
{ "$": "auto_text_key", "code": 2529, "label": "ৡ" },
|
||||
{ "$": "auto_text_key", "code": 2530, "label": "ৢ" },
|
||||
{ "$": "auto_text_key", "code": 2531, "label": "ৣ" }
|
||||
]
|
||||
},
|
||||
"ু": {
|
||||
"main": { "$": "auto_text_key", "code": 2441, "label": "উ" }
|
||||
},
|
||||
"ি": {
|
||||
"main": { "$": "auto_text_key", "code": 2439, "label": "ই" }
|
||||
},
|
||||
"া": {
|
||||
"main": { "$": "auto_text_key", "code": 2438, "label": "আ" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 2437, "label": "অ" }
|
||||
]
|
||||
},
|
||||
"্": {
|
||||
"main": { "$": "auto_text_key", "code": 2433, "label": "ঁ" }
|
||||
},
|
||||
"ব": {
|
||||
"main": { "$": "auto_text_key", "code": 2477, "label": "ভ" }
|
||||
},
|
||||
"ক": {
|
||||
"main": { "$": "auto_text_key", "code": 2454, "label": "খ" }
|
||||
},
|
||||
"ত": {
|
||||
"main": { "$": "auto_text_key", "code": 2469, "label": "থ" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 2510, "label": "ৎ" }
|
||||
]
|
||||
},
|
||||
"দ": {
|
||||
"main": { "$": "auto_text_key", "code": 2471, "label": "ধ" }
|
||||
},
|
||||
"ো": {
|
||||
"main": { "$": "auto_text_key", "code": 2451, "label": "ও" }
|
||||
},
|
||||
"ে": {
|
||||
"main": { "$": "auto_text_key", "code": 2447, "label": "এ" }
|
||||
},
|
||||
"র": {
|
||||
"main": { "$": "auto_text_key", "code": 2482, "label": "ল" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": "র্য" }
|
||||
]
|
||||
},
|
||||
"ন": {
|
||||
"main": { "$": "auto_text_key", "code": 2467, "label": "ণ" }
|
||||
},
|
||||
"স": {
|
||||
"main": { "$": "auto_text_key", "code": 2487, "label": "ষ" }
|
||||
},
|
||||
"ম": {
|
||||
"main": { "$": "auto_text_key", "code": 2486, "label": "শ" }
|
||||
},
|
||||
"ূ": {
|
||||
"main": { "$": "auto_text_key", "code": 2442, "label": "ঊ" }
|
||||
},
|
||||
"ী": {
|
||||
"main": { "$": "auto_text_key", "code": 2440, "label": "ঈ" }
|
||||
},
|
||||
"ঁ": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 2493, "label": "ঽ" },
|
||||
{ "$": "auto_text_key", "code": 2544, "label": "ৰ" },
|
||||
{ "$": "auto_text_key", "code": 2545, "label": "ৱ" },
|
||||
{ "$": "auto_text_key", "code": 2492, "label": "়" },
|
||||
{ "$": "auto_text_key", "code": 2554, "label": "৺" },
|
||||
{ "$": "auto_text_key", "code": 2519, "label": "ৗ" }
|
||||
]
|
||||
},
|
||||
"ৌ": {
|
||||
"main": { "$": "auto_text_key", "code": 2452, "label": "ঔ" }
|
||||
},
|
||||
"ৈ": {
|
||||
"main": { "$": "auto_text_key", "code": 2448, "label": "ঐ" }
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 2404, "label": "।" },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 2435, "label": "ঃ" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".com.bd" },
|
||||
{ "code": -255, "label": ".bd" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,41 +2,74 @@
|
||||
"all": {
|
||||
"α": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 940, "label": "ά" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 940, "label": "ά" },
|
||||
"upper": { "code": 902, "label": "Ά" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"ε": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 941, "label": "έ" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 941, "label": "έ" },
|
||||
"upper": { "code": 904, "label": "Έ" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"η": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 942, "label": "ή" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 942, "label": "ή" },
|
||||
"upper": { "code": 905, "label": "Ή" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"ι": {
|
||||
"main": { "$": "auto_text_key", "code": 943, "label": "ί" },
|
||||
"main": { "$": "case_selector",
|
||||
"lower": { "code": 943, "label": "ί" },
|
||||
"upper": { "code": 906, "label": "Ί" }
|
||||
},
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 912, "label": "ΐ" },
|
||||
{ "$": "auto_text_key", "code": 970, "label": "ϊ" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 912, "label": "ΐ" },
|
||||
"upper": { "$": "multi_text_key", "codePoints": [921, 776, 769], "label": "Ϊ́" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 970, "label": "ϊ" },
|
||||
"upper": { "code": 938, "label": "Ϊ" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"ο": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 972, "label": "ό" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 972, "label": "ό" },
|
||||
"upper": { "code": 908, "label": "Ό" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"υ": {
|
||||
"main": { "$": "auto_text_key", "code": 973, "label": "ύ" },
|
||||
"main": { "$": "case_selector",
|
||||
"lower": { "code": 973, "label": "ύ" },
|
||||
"upper": { "code": 910, "label": "Ύ" }
|
||||
},
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 944, "label": "ΰ" },
|
||||
{ "$": "auto_text_key", "code": 971, "label": "ϋ" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 944, "label": "ΰ" },
|
||||
"upper": { "$": "multi_text_key", "codePoints": [933, 776, 769], "label": "Ϋ́" }
|
||||
},
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 971, "label": "ϋ" },
|
||||
"upper": { "code": 939, "label": "Ϋ" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"ω": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 974, "label": "ώ" }
|
||||
{ "$": "case_selector",
|
||||
"lower": { "code": 974, "label": "ώ" },
|
||||
"upper": { "code": 911, "label": "Ώ" }
|
||||
}
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"all": {
|
||||
"a": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 228, "label": "ä" },
|
||||
{ "$": "auto_text_key", "code": 225, "label": "á" },
|
||||
{ "$": "auto_text_key", "code": 226, "label": "â" },
|
||||
{ "$": "auto_text_key", "code": 227, "label": "ã" },
|
||||
{ "$": "auto_text_key", "code": 257, "label": "ā" },
|
||||
{ "$": "auto_text_key", "code": 229, "label": "å" },
|
||||
{ "$": "auto_text_key", "code": 230, "label": "æ" },
|
||||
{ "$": "auto_text_key", "code": 224, "label": "à" }
|
||||
]
|
||||
},
|
||||
"e": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 233, "label": "é" },
|
||||
{ "$": "auto_text_key", "code": 275, "label": "ē" },
|
||||
{ "$": "auto_text_key", "code": 281, "label": "ę" },
|
||||
{ "$": "auto_text_key", "code": 279, "label": "ė" },
|
||||
{ "$": "auto_text_key", "code": 232, "label": "è" },
|
||||
{ "$": "auto_text_key", "code": 235, "label": "ë" },
|
||||
{ "$": "auto_text_key", "code": 234, "label": "ê" }
|
||||
]
|
||||
},
|
||||
"i": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 237, "label": "í" },
|
||||
{ "$": "auto_text_key", "code": 299, "label": "ī" },
|
||||
{ "$": "auto_text_key", "code": 236, "label": "ì" },
|
||||
{ "$": "auto_text_key", "code": 303, "label": "į" },
|
||||
{ "$": "auto_text_key", "code": 238, "label": "î" },
|
||||
{ "$": "auto_text_key", "code": 239, "label": "ï" }
|
||||
]
|
||||
},
|
||||
"o": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 333, "label": "ō" },
|
||||
{ "$": "auto_text_key", "code": 339, "label": "œ" },
|
||||
{ "$": "auto_text_key", "code": 243, "label": "ó" },
|
||||
{ "$": "auto_text_key", "code": 245, "label": "õ" },
|
||||
{ "$": "auto_text_key", "code": 242, "label": "ò" },
|
||||
{ "$": "auto_text_key", "code": 244, "label": "ô" },
|
||||
{ "$": "auto_text_key", "code": 248, "label": "ø" }
|
||||
]
|
||||
},
|
||||
"s": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 353, "label": "š" },
|
||||
{ "$": "auto_text_key", "code": 223, "label": "ß" },
|
||||
{ "$": "auto_text_key", "code": 347, "label": "ś" }
|
||||
]
|
||||
},
|
||||
"u": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
{ "$": "auto_text_key", "code": 363, "label": "ū" },
|
||||
{ "$": "auto_text_key", "code": 251, "label": "û" },
|
||||
{ "$": "auto_text_key", "code": 250, "label": "ú" },
|
||||
{ "$": "auto_text_key", "code": 249, "label": "ù" }
|
||||
]
|
||||
},
|
||||
"z": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 382, "label": "ž" },
|
||||
{ "$": "auto_text_key", "code": 380, "label": "ż" },
|
||||
{ "$": "auto_text_key", "code": 378, "label": "ź" }
|
||||
]
|
||||
},
|
||||
"ä": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 230, "label": "æ" }
|
||||
]
|
||||
},
|
||||
"ö": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 248, "label": "ø" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" },
|
||||
{ "code": -255, "label": ".ee" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
},
|
||||
"ک": {
|
||||
"relevant": [
|
||||
{ "code": 1603, "label": "ك" },
|
||||
{ "code": 1706, "label": "ڪ"}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,68 +1,62 @@
|
||||
{
|
||||
"all": {
|
||||
"a": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 225, "label": "á" }
|
||||
]
|
||||
"main": { "$": "auto_text_key","code" : 225, "label": "á" }
|
||||
},
|
||||
"e": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 233, "label": "é" }
|
||||
]
|
||||
"main": {"$": "auto_text_key", "code" : 233, "label": "é" }
|
||||
},
|
||||
"i": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 237, "label": "í" }
|
||||
]
|
||||
"main": { "$": "auto_text_key" ,"code" : 237, "label": "í" }
|
||||
},
|
||||
"o": {
|
||||
"main": { "$": "auto_text_key", "code" : 246, "label": "ö" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 243, "label": "ó" },
|
||||
{ "$": "auto_text_key", "code": 246, "label": "ö" },
|
||||
{ "$": "auto_text_key", "code": 337, "label": "ő" }
|
||||
{ "$": "auto_text_key", "code" : 243, "label": "ó" },
|
||||
{ "$": "auto_text_key", "code" : 337, "label": "ő" }
|
||||
]
|
||||
},
|
||||
"ö": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 337, "label": "ő" }
|
||||
{ "$": "auto_text_key", "code" : 337, "label": "ő" }
|
||||
]
|
||||
},
|
||||
"u": {
|
||||
"main": { "$": "auto_text_key", "code" : 252, "label": "ü" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 250, "label": "ú" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
{ "$": "auto_text_key", "code": 369, "label": "ű" }
|
||||
{ "$": "auto_text_key", "code" : 250, "label": "ú" },
|
||||
{ "$": "auto_text_key", "code" : 369, "label": "ű" }
|
||||
]
|
||||
},
|
||||
"ü": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 369, "label": "ű" }
|
||||
{ "$": "auto_text_key", "code" : 369, "label": "ű" }
|
||||
]
|
||||
},
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"main": { "code" : 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "code" : 37, "label": "%" },
|
||||
{ "code" : 38, "label": "&" },
|
||||
{ "code" : 43, "label": "+" },
|
||||
{ "code" : 34, "label": "\"" },
|
||||
{ "code" : 45, "label": "-" },
|
||||
{ "code" : 58, "label": ":" },
|
||||
{ "code" : 39, "label": "'" },
|
||||
{ "code" : 64, "label": "@" },
|
||||
{ "code" : 59, "label": ";" },
|
||||
{ "code" : 47, "label": "/" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
"ltr": { "code" : 40, "label": "(" },
|
||||
"rtl": { "code" : 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
"ltr": { "code" : 41, "label": ")" },
|
||||
"rtl": { "code" : 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
{ "code" : 35, "label": "#" },
|
||||
{ "code" : 33, "label": "!" },
|
||||
{ "code" : 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -74,7 +68,7 @@
|
||||
{ "code": -255, "label": ".net" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".eu" },
|
||||
{ "code": -255, "label": ".gov.hu" }
|
||||
{ "code": -255, "label": ".gov.hu" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"all": {
|
||||
"w": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 695, "label": "ʷ" }
|
||||
]
|
||||
},
|
||||
"e": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 234, "label": "ê" },
|
||||
{ "$": "auto_text_key", "code": 578, "label": "ɂ" },
|
||||
{ "$": "auto_text_key", "code": 233, "label": "é" },
|
||||
{ "$": "auto_text_key", "code": 232, "label": "è" },
|
||||
{ "$": "auto_text_key", "code": 235, "label": "ë" },
|
||||
{ "$": "auto_text_key", "code": 477, "label": "ǝ" },
|
||||
{ "$": "auto_text_key", "code": 603, "label": "ɛ" }
|
||||
]
|
||||
},
|
||||
"r": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7771, "label": "ṛ" }
|
||||
]
|
||||
},
|
||||
"t": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7789, "label": "ṭ" }
|
||||
]
|
||||
},
|
||||
"y": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 255, "label": "ÿ" }
|
||||
]
|
||||
},
|
||||
"u": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 118, "label": "v" },
|
||||
{ "$": "auto_text_key", "code": 251, "label": "û" },
|
||||
{ "$": "auto_text_key", "code": 249, "label": "ù" },
|
||||
{ "$": "auto_text_key", "code": 252, "label": "ü" }
|
||||
]
|
||||
},
|
||||
"i": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 239, "label": "ï" },
|
||||
{ "$": "auto_text_key", "code": 238, "label": "î" }
|
||||
]
|
||||
},
|
||||
"o": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 339, "label": "œ" },
|
||||
{ "$": "auto_text_key", "code": 244, "label": "ô" }
|
||||
]
|
||||
},
|
||||
"a": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 259, "label": "ă" },
|
||||
{ "$": "auto_text_key", "code": 224, "label": "à" },
|
||||
{ "$": "auto_text_key", "code": 226, "label": "â" },
|
||||
{ "$": "auto_text_key", "code": 230, "label": "æ" }
|
||||
]
|
||||
},
|
||||
"s": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7779, "label": "ṣ" },
|
||||
{ "$": "auto_text_key", "code": 353, "label": "š" }
|
||||
]
|
||||
},
|
||||
"d": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7693, "label": "ḍ" }
|
||||
]
|
||||
},
|
||||
"g": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 487, "label": "ǧ" },
|
||||
{ "$": "auto_text_key", "code": 611, "label": "ɣ" }
|
||||
]
|
||||
},
|
||||
"h": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7717, "label": "ḥ" }
|
||||
]
|
||||
},
|
||||
"j": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 496, "label": "ǰ" }
|
||||
]
|
||||
},
|
||||
"l": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7735, "label": "ḷ" }
|
||||
]
|
||||
},
|
||||
"z": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7827, "label": "ẓ" },
|
||||
{ "$": "auto_text_key", "code": 382, "label": "ž" }
|
||||
]
|
||||
},
|
||||
"c": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 269, "label": "č" },
|
||||
{ "$": "auto_text_key", "code": 231, "label": "ç" }
|
||||
]
|
||||
},
|
||||
"b": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 7685, "label": "ḅ" },
|
||||
{ "$": "auto_text_key", "code": 112, "label": "p" }
|
||||
]
|
||||
},
|
||||
"n": {
|
||||
"relevant":[
|
||||
{ "$": "auto_text_key", "code": 331, "label": "ŋ" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".dz" },
|
||||
{ "code": -255, "label": ".fr" },
|
||||
{ "code": -255, "label": ".gov" },
|
||||
{ "code": -255, "label": ".edu" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,8 @@
|
||||
},
|
||||
"z": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 378, "label": "ź" },
|
||||
{ "$": "auto_text_key", "code": 380, "label": "ż" }
|
||||
{ "$": "auto_text_key", "code": 380, "label": "ż" },
|
||||
{ "$": "auto_text_key", "code": 378, "label": "ź" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"all": {
|
||||
"c": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 269, "label": "č" },
|
||||
]
|
||||
},
|
||||
"s": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 353, "label": "š" }
|
||||
]
|
||||
},
|
||||
"z": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 382, "label": "ž" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 43, "label": "+" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "code": 59, "label": ";" },
|
||||
{ "code": 47, "label": "/" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".eu" },
|
||||
{ "code": -255, "label": ".si" },
|
||||
{ "code": -255, "label": ".org" },
|
||||
{ "code": -255, "label": ".net" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"all": {
|
||||
"a": {
|
||||
"main": { "$": "auto_text_key", "code": 226, "label": "â" }
|
||||
},
|
||||
"c": {
|
||||
"main": { "$": "auto_text_key", "code": 231, "label": "ç" }
|
||||
},
|
||||
@@ -10,13 +13,19 @@
|
||||
"main": { "$": "case_selector",
|
||||
"lower": { "code": 305, "label": "ı" },
|
||||
"upper": { "code": 73, "label": "I" }
|
||||
}
|
||||
},
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 238, "label": "î" }
|
||||
]
|
||||
},
|
||||
"ı": {
|
||||
"main": { "$": "case_selector",
|
||||
"lower": { "code": 105, "label": "i" },
|
||||
"upper": { "code": 304, "label": "İ" }
|
||||
}
|
||||
},
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 238, "label": "î" }
|
||||
]
|
||||
},
|
||||
"o": {
|
||||
"main": { "$": "auto_text_key", "code": 246, "label": "ö" }
|
||||
@@ -25,7 +34,10 @@
|
||||
"main": { "$": "auto_text_key", "code": 351, "label": "ş" }
|
||||
},
|
||||
"u": {
|
||||
"main": { "$": "auto_text_key", "code": 252, "label": "ü" }
|
||||
"main": { "$": "auto_text_key", "code": 252, "label": "ü" },
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 251, "label": "û" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"all": {
|
||||
"о": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1255, "label": "ӧ" }
|
||||
]
|
||||
},
|
||||
"з": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1247, "label": "ӟ" }
|
||||
]
|
||||
},
|
||||
"ж": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1245, "label": "ӝ" }
|
||||
]
|
||||
},
|
||||
"ч": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1269, "label": "ӵ" }
|
||||
]
|
||||
},
|
||||
"и": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1253, "label": "ӥ" }
|
||||
]
|
||||
},
|
||||
"е": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1105, "label": "ё" }
|
||||
]
|
||||
},
|
||||
"ь": {
|
||||
"relevant": [
|
||||
{ "$": "auto_text_key", "code": 1098, "label": "ъ" }
|
||||
]
|
||||
},
|
||||
"~right": {
|
||||
"main": { "code": 44, "label": "," },
|
||||
"relevant": [
|
||||
{ "code": 38, "label": "&" },
|
||||
{ "code": 37, "label": "%" },
|
||||
{ "code": 34, "label": "\"" },
|
||||
{ "code": 45, "label": "-" },
|
||||
{ "code": 58, "label": ":" },
|
||||
{ "code": 39, "label": "'" },
|
||||
{ "code": 64, "label": "@" },
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 40, "label": "(" },
|
||||
"rtl": { "code": 41, "label": "(" }
|
||||
},
|
||||
{ "$": "layout_direction_selector",
|
||||
"ltr": { "code": 41, "label": ")" },
|
||||
"rtl": { "code": 40, "label": ")" }
|
||||
},
|
||||
{ "code": 35, "label": "#" },
|
||||
{ "code": 33, "label": "!" },
|
||||
{ "code": 63, "label": "?" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"uri": {
|
||||
"~right": {
|
||||
"main": { "code": -255, "label": ".com" },
|
||||
"relevant": [
|
||||
{ "code": -255, "label": ".ru" },
|
||||
{ "code": -255, "label": ".udm.ru" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"$": "ime.extension.languagepack",
|
||||
"meta": {
|
||||
"id": "org.florisboard.hanshapebasedbasicpack",
|
||||
"version": "0.0.0",
|
||||
"title": "Default barebones Chinese shape-based pack",
|
||||
"description": "默认中文形码语言包 / 預設中文形碼語言包 / Default barebones Chinese shape-based language pack which are always available.\n请访问下面的主页链接下载更多输入法 / 請訪問下面的主頁鏈接下載更多輸入法 / Please visit the homepage linked below to download more input methods.",
|
||||
"maintainers": [ "patrickgold <patrick@patrickgold.dev>", "waelwindows", "moonbeamcelery" ],
|
||||
"homepage": "https://github.com/florisboard/florisboard/blob/master/LANGUAGEPACKS-CHINESE.md#default-barebones-chinese-shape-based-pack",
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": "zh_CN_zhengma",
|
||||
"label": "中文 (中国) [郑码] / Chinese (China) [ZHENGMA]",
|
||||
"authors": [ "waelwindows", "moonbeamcelery" ],
|
||||
"hanShapeBasedKeyCode": "abcdefghijklmnopqrstuvwxyz"
|
||||
},
|
||||
{
|
||||
"id": "zh_TW_boshiamy",
|
||||
"label": "中文 (台灣) [嘸蝦米] / Chinese (Taiwan) [BOSHIAMY]",
|
||||
"authors": [ "waelwindows", "moonbeamcelery" ],
|
||||
"hanShapeBasedKeyCode": ",.'abcdefghijklmnopqrstuvwxyz[]"
|
||||
},
|
||||
{
|
||||
"id": "zh_TW_cangjielarge",
|
||||
"label": "中文 (台灣) [倉頡-大字庫] / Chinese (Taiwan) [CANGJIELARGE]",
|
||||
"authors": [ "waelwindows", "moonbeamcelery" ],
|
||||
"hanShapeBasedKeyCode": "abcdefghijklmnopqrstuvwxyz&"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$": "ime.extension.languagepack",
|
||||
"meta": {
|
||||
"id": "org.florisboard.languagepack",
|
||||
"version": "0.0.0",
|
||||
"title": "Default language pack",
|
||||
"description": "Default language pack which are always available.",
|
||||
"maintainers": [ "patrickgold <patrick@patrickgold.dev>" ],
|
||||
"license": "apache-2.0"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": "de_DE_neobone",
|
||||
"label": "Deutsch (Deutschland) [NEOBONE] / German (Germany) [NEOBONE]",
|
||||
"authors": [ "patrickgold" ]
|
||||
},
|
||||
{
|
||||
"id": "ja_JP_jis",
|
||||
"label": "日本語 (日本) [JIS] / Japanese (Japan) [JIS]",
|
||||
"authors": [ "patrickgold" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -64,36 +64,65 @@
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"smartbar-shared-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"smartbar-extended-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"smartbar-action-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"smartbar-action-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
},
|
||||
"smartbar-action-tile": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-actions-editor": {
|
||||
"background": "var(--background)",
|
||||
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
|
||||
},
|
||||
"smartbar-actions-editor-header": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-actions-editor-subheader": {
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
@@ -183,6 +212,10 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#00000011"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#e8f5e9",
|
||||
"foreground": "#424242"
|
||||
|
||||
@@ -63,35 +63,65 @@
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"smartbar-shared-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()"
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"smartbar-extended-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"smartbar-action-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"smartbar-action-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
},
|
||||
"smartbar-action-tile": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#12121248"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-actions-editor": {
|
||||
"background": "var(--background)",
|
||||
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
|
||||
},
|
||||
"smartbar-actions-editor-header": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-actions-editor-subheader": {
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
@@ -181,6 +211,10 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#00000011"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#e8f5e9",
|
||||
"foreground": "#424242"
|
||||
|
||||
@@ -64,36 +64,65 @@
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"smartbar-shared-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"smartbar-extended-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"smartbar-action-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"smartbar-action-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-action-tile": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-actions-editor": {
|
||||
"background": "var(--background)",
|
||||
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
|
||||
},
|
||||
"smartbar-actions-editor-header": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-actions-editor-subheader": {
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
@@ -183,6 +212,10 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#ffffff11"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#1b5e20",
|
||||
"foreground": "#eeeeee"
|
||||
|
||||
@@ -63,35 +63,65 @@
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"smartbar-shared-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()"
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"smartbar-extended-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"smartbar-action-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"smartbar-action-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-action-tile": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-actions-editor": {
|
||||
"background": "var(--background)",
|
||||
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
|
||||
},
|
||||
"smartbar-actions-editor-header": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-actions-editor-subheader": {
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
@@ -181,6 +211,10 @@
|
||||
"foreground": "var(--primary)"
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#ffffff11"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#1b5e20",
|
||||
"foreground": "#eeeeee"
|
||||
|
||||
@@ -64,36 +64,65 @@
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"smartbar-shared-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"smartbar-extended-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"smartbar-action-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"smartbar-action-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-action-tile": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-actions-editor": {
|
||||
"background": "var(--background)",
|
||||
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
|
||||
},
|
||||
"smartbar-actions-editor-header": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-actions-editor-subheader": {
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
@@ -183,6 +212,10 @@
|
||||
"foreground": "var(--primary-variant)"
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#ffffff11"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#000000",
|
||||
"foreground": "#eeeeee"
|
||||
|
||||
@@ -63,36 +63,65 @@
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
|
||||
"smartbar-primary-actions-toggle": {
|
||||
"smartbar-shared-actions-toggle": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-secondary-actions-toggle": {
|
||||
"smartbar-extended-actions-toggle": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-surface-variant)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-quick-action": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"shape": "circle()"
|
||||
},
|
||||
"smartbar-key": {
|
||||
"smartbar-action-key": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-key:pressed": {
|
||||
"smartbar-action-key:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-key:disabled": {
|
||||
"smartbar-action-key:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-action-tile": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "18sp",
|
||||
"shape": "var(--shape)"
|
||||
},
|
||||
"smartbar-action-tile:pressed": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)"
|
||||
},
|
||||
"smartbar-action-tile:disabled": {
|
||||
"background": "transparent",
|
||||
"foreground": "#dcdcdc48"
|
||||
},
|
||||
"smartbar-actions-overflow-customize-button": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "14sp",
|
||||
"shape": "circle()",
|
||||
"shadow-elevation": "2dp"
|
||||
},
|
||||
"smartbar-actions-editor": {
|
||||
"background": "var(--background)",
|
||||
"shape": "rounded-corner(24dp, 24dp, 0dp, 0dp)"
|
||||
},
|
||||
"smartbar-actions-editor-header": {
|
||||
"background": "var(--surface)",
|
||||
"foreground": "var(--on-surface)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-actions-editor-subheader": {
|
||||
"foreground": "var(--on-background)",
|
||||
"font-size": "16sp"
|
||||
},
|
||||
"smartbar-candidate-word": {
|
||||
"background": "transparent",
|
||||
"foreground": "var(--on-background)",
|
||||
@@ -182,6 +211,10 @@
|
||||
"foreground": "var(--primary-variant)"
|
||||
},
|
||||
|
||||
"incognito-mode-indicator": {
|
||||
"foreground": "#ffffff11"
|
||||
},
|
||||
|
||||
"one-handed-panel": {
|
||||
"background": "#000000",
|
||||
"foreground": "#eeeeee"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"uniqueId": "pictogrammers-material-icons",
|
||||
"name": "Pictogrammers Material Icons",
|
||||
"developers": [
|
||||
{
|
||||
"name": "Pictogrammers Icon Group",
|
||||
"organisationUrl": "https://pictogrammers.com"
|
||||
}
|
||||
],
|
||||
"website": "https://github.com/Templarian/MaterialDesign",
|
||||
"licenses": [
|
||||
"Apache-2.0"
|
||||
]
|
||||
}
|
||||
@@ -1,34 +1,19 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
cmake_minimum_required(VERSION 3.10.2)
|
||||
project(florisboard)
|
||||
|
||||
project("florisboard")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
include_directories(.)
|
||||
|
||||
### ICU4C ###
|
||||
include_directories(../icu4c/prebuilt/include)
|
||||
set(JNI_LIBS ${CMAKE_SOURCE_DIR}/../icu4c/prebuilt/jniLibs/${ANDROID_ABI})
|
||||
add_library(ICU::data STATIC IMPORTED)
|
||||
set_property(TARGET ICU::data PROPERTY IMPORTED_LOCATION "${JNI_LIBS}/libicudata.a")
|
||||
add_library(ICU::uc STATIC IMPORTED)
|
||||
set_property(TARGET ICU::uc PROPERTY IMPORTED_LOCATION "${JNI_LIBS}/libicuuc.a")
|
||||
|
||||
### FlorisBoard ###
|
||||
add_subdirectory(nuspell)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(ime/nlp)
|
||||
add_subdirectory(ime/spelling)
|
||||
add_subdirectory(nlp)
|
||||
|
||||
add_library(
|
||||
florisboard-native
|
||||
SHARED
|
||||
dev_patrickgold_florisboard_FlorisApplication.cpp
|
||||
dev_patrickgold_florisboard_ime_nlp_SuggestionList.cpp
|
||||
dev_patrickgold_florisboard_ime_spelling_SpellingDict.cpp
|
||||
)
|
||||
|
||||
target_compile_options(florisboard-native PRIVATE -ffunction-sections -fdata-sections -fexceptions)
|
||||
@@ -39,10 +24,6 @@ target_link_libraries(
|
||||
# Sources
|
||||
android
|
||||
log
|
||||
ICU::uc
|
||||
ICU::data
|
||||
Nuspell::nuspell
|
||||
fl::nlp::core
|
||||
utils
|
||||
ime-nlp
|
||||
ime-spelling
|
||||
)
|
||||
|
||||
@@ -20,34 +20,16 @@
|
||||
#include <unicode/udata.h>
|
||||
#include "utils/jni_utils.h"
|
||||
|
||||
#include "fl_icuext.hpp"
|
||||
|
||||
#pragma ide diagnostic ignored "UnusedLocalVariable"
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_dev_patrickgold_florisboard_FlorisApplication_00024Companion_nativeInitICUData(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject path) {
|
||||
JNIEnv *env, jobject thiz, jobject path)
|
||||
{
|
||||
auto path_str = utils::j2std_string(env, path);
|
||||
std::ifstream in_file(path_str, std::ios::in | std::ios::binary);
|
||||
if (!in_file) {
|
||||
return U_FILE_ACCESS_ERROR;
|
||||
}
|
||||
in_file.seekg(0, std::ios::end);
|
||||
size_t size = in_file.tellg();
|
||||
if (size <= 0) {
|
||||
return U_FILE_ACCESS_ERROR;
|
||||
}
|
||||
in_file.seekg(0, std::ios::beg);
|
||||
char *icu_data = new char[size + 1];
|
||||
in_file.read(icu_data, size);
|
||||
if (!in_file) {
|
||||
in_file.close();
|
||||
return U_FILE_ACCESS_ERROR;
|
||||
}
|
||||
icu_data[size] = 0;
|
||||
in_file.close();
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
udata_setCommonData(reinterpret_cast<void *>(icu_data), &status);
|
||||
auto status = fl::icuext::loadAndSetCommonData(path_str);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1,123 +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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include "ime/nlp/suggestion_list.h"
|
||||
|
||||
#pragma ide diagnostic ignored "UnusedLocalVariable"
|
||||
|
||||
using namespace ime::nlp;
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeInitialize(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jint max_size) {
|
||||
auto *suggestionList = new SuggestionList(max_size);
|
||||
return reinterpret_cast<jlong>(suggestionList);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeDispose(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr) {
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
suggestionList->clear();
|
||||
delete suggestionList;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeAdd(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr,
|
||||
jstring word,
|
||||
jint freq) {
|
||||
const char *cWord = env->GetStringUTFChars(word, nullptr);
|
||||
word_t stdWord = word_t(cWord);
|
||||
env->ReleaseStringUTFChars(word, cWord);
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
return suggestionList->add(std::move(stdWord), freq);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeClear(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr) {
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
suggestionList->clear();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeContains(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr,
|
||||
jstring element) {
|
||||
const char *cWord = env->GetStringUTFChars(element, nullptr);
|
||||
const word_t stdWord = word_t(cWord);
|
||||
env->ReleaseStringUTFChars(element, cWord);
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
return suggestionList->containsWord(stdWord);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeGetOrNull(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr,
|
||||
jint index) {
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
auto weightedToken = suggestionList->get(index);
|
||||
if (weightedToken == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return env->NewStringUTF(weightedToken->data.c_str());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeSize(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr) {
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
return suggestionList->size();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeGetIsPrimaryTokenAutoInsert(
|
||||
JNIEnv *env, jobject thiz, jlong native_ptr) {
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
return suggestionList->isPrimaryTokenAutoInsert;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_SuggestionList_00024Companion_nativeSetIsPrimaryTokenAutoInsert(
|
||||
JNIEnv *env, jobject thiz, jlong native_ptr, jboolean v) {
|
||||
auto *suggestionList = reinterpret_cast<SuggestionList *>(native_ptr);
|
||||
suggestionList->isPrimaryTokenAutoInsert = v;
|
||||
}
|
||||
@@ -1,90 +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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <algorithm>
|
||||
#include "ime/spelling/spellingdict.h"
|
||||
#include "utils/jni_utils.h"
|
||||
|
||||
#pragma ide diagnostic ignored "UnusedLocalVariable"
|
||||
|
||||
using namespace ime::spellcheck;
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeInitialize(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject base_path) {
|
||||
auto strBasePath = utils::j2std_string(env, base_path);
|
||||
|
||||
auto *spellingDict = SpellingDict::load(strBasePath);
|
||||
|
||||
if (spellingDict == nullptr) {
|
||||
return 0L;
|
||||
} else {
|
||||
return reinterpret_cast<jlong>(spellingDict);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeDispose(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr) {
|
||||
auto spellingDict = reinterpret_cast<SpellingDict *>(native_ptr);
|
||||
|
||||
delete spellingDict;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeSpell(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr,
|
||||
jobject word) {
|
||||
auto strWord = utils::j2std_string(env, word);
|
||||
|
||||
auto spellingDict = reinterpret_cast<SpellingDict *>(native_ptr);
|
||||
auto result = spellingDict->spell(strWord);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_spelling_SpellingDict_00024Companion_nativeSuggest(
|
||||
JNIEnv *env,
|
||||
jobject thiz,
|
||||
jlong native_ptr,
|
||||
jobject word,
|
||||
jint limit) {
|
||||
auto strWord = utils::j2std_string(env, word);
|
||||
|
||||
auto spellingDict = reinterpret_cast<SpellingDict *>(native_ptr);
|
||||
auto result = spellingDict->suggest(strWord);
|
||||
auto retSize = std::min(result.size(), (size_t)std::max(0, limit));
|
||||
|
||||
jclass jByteArrayClass = env->FindClass("java/nio/ByteBuffer");
|
||||
jobjectArray jSuggestions = env->NewObjectArray(retSize, jByteArrayClass, nullptr);
|
||||
for (int n = 0; n < retSize; n++) {
|
||||
env->SetObjectArrayElement(jSuggestions, n, utils::std2j_string(env, result[n]));
|
||||
}
|
||||
|
||||
return jSuggestions;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
add_library(
|
||||
# Name
|
||||
ime-nlp
|
||||
|
||||
# Headers
|
||||
nlp.h
|
||||
token.h
|
||||
suggestion_list.h
|
||||
|
||||
# Sources
|
||||
token.cpp
|
||||
suggestion_list.cpp
|
||||
)
|
||||
@@ -1,32 +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.
|
||||
*/
|
||||
|
||||
#ifndef FLORISBOARD_NLP_H
|
||||
#define FLORISBOARD_NLP_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ime::nlp {
|
||||
|
||||
typedef std::string word_t;
|
||||
typedef uint16_t freq_t;
|
||||
|
||||
static const freq_t FREQ_VALUE_MASK = 0xFF;
|
||||
static const freq_t FREQ_POSSIBLY_OFFENSIVE = 0x01;
|
||||
|
||||
} // namespace ime::nlp
|
||||
|
||||
#endif // FLORISBOARD_NLP_H
|
||||
@@ -1,98 +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.
|
||||
*/
|
||||
|
||||
#include "suggestion_list.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace ime::nlp;
|
||||
|
||||
SuggestionList::SuggestionList(size_t _maxSize) :
|
||||
maxSize(_maxSize), internalSize(0), tokens(_maxSize), isPrimaryTokenAutoInsert(false)
|
||||
{ }
|
||||
|
||||
SuggestionList::~SuggestionList() = default;
|
||||
|
||||
bool SuggestionList::add(word_t &&word, freq_t &&freq) {
|
||||
auto entryIndex = indexOfWord(word);
|
||||
if (entryIndex.has_value()) {
|
||||
// Word exists already
|
||||
auto entry = tokens[entryIndex.value()];
|
||||
if (entry.freq < freq) {
|
||||
// Need to update freq
|
||||
entry.freq = freq;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (internalSize < maxSize) {
|
||||
tokens[internalSize++] = WeightedToken(std::move(word), freq);
|
||||
} else {
|
||||
auto last = tokens[internalSize - 1];
|
||||
if (last.freq < freq) {
|
||||
tokens[internalSize - 1] = WeightedToken(std::move(word), freq);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(tokens.begin(), tokens.begin() + internalSize, std::greater<>());
|
||||
return true;
|
||||
}
|
||||
|
||||
void SuggestionList::clear() {
|
||||
internalSize = 0;
|
||||
isPrimaryTokenAutoInsert = false;
|
||||
}
|
||||
|
||||
bool SuggestionList::contains(const WeightedToken &element) const {
|
||||
return indexOf(element).has_value();
|
||||
}
|
||||
|
||||
bool SuggestionList::containsWord(const word_t &word) const {
|
||||
return indexOfWord(word).has_value();
|
||||
}
|
||||
|
||||
const WeightedToken *SuggestionList::get(size_t index) const {
|
||||
if (index < 0 || index >= internalSize) return nullptr;
|
||||
return &tokens[index];
|
||||
}
|
||||
|
||||
std::optional<size_t> SuggestionList::indexOf(const WeightedToken &element) const {
|
||||
for (size_t n = 0; n < internalSize; n++) {
|
||||
if (element == tokens[n]) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<size_t> SuggestionList::indexOfWord(const word_t &word) const {
|
||||
for (size_t n = 0; n < internalSize; n++) {
|
||||
if (word == tokens[n].data) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool SuggestionList::isEmpty() const {
|
||||
return internalSize == 0;
|
||||
}
|
||||
|
||||
size_t SuggestionList::size() const {
|
||||
return internalSize;
|
||||
}
|
||||
@@ -1,51 +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.
|
||||
*/
|
||||
|
||||
#ifndef FLORISBOARD_SUGGESTION_LIST_H
|
||||
#define FLORISBOARD_SUGGESTION_LIST_H
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include "token.h"
|
||||
|
||||
namespace ime::nlp {
|
||||
|
||||
class SuggestionList {
|
||||
public:
|
||||
SuggestionList(size_t _maxSize);
|
||||
~SuggestionList();
|
||||
|
||||
bool add(word_t &&word, freq_t &&freq);
|
||||
void clear();
|
||||
bool contains(const WeightedToken &element) const;
|
||||
bool containsWord(const word_t &word) const;
|
||||
const WeightedToken *get(size_t index) const;
|
||||
std::optional<size_t> indexOf(const WeightedToken &element) const;
|
||||
std::optional<size_t> indexOfWord(const word_t &word) const;
|
||||
bool isEmpty() const;
|
||||
size_t size() const;
|
||||
|
||||
bool isPrimaryTokenAutoInsert;
|
||||
|
||||
private:
|
||||
std::vector<WeightedToken> tokens;
|
||||
size_t internalSize;
|
||||
size_t maxSize;
|
||||
};
|
||||
|
||||
} // namespace ime::nlp
|
||||
|
||||
#endif // FLORISBOARD_SUGGESTION_LIST_H
|
||||
@@ -1,61 +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.
|
||||
*/
|
||||
|
||||
#include "token.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace ime::nlp {
|
||||
|
||||
Token::Token() : data() {}
|
||||
Token::Token(word_t &&_data) : data(std::move(_data)) {}
|
||||
|
||||
bool operator==(const Token &t1, const Token &t2) {
|
||||
return t1.data == t2.data;
|
||||
}
|
||||
|
||||
bool operator!=(const Token &t1, const Token &t2) {
|
||||
return !(t1 == t2);
|
||||
}
|
||||
|
||||
WeightedToken::WeightedToken() : Token(), freq(0) {}
|
||||
WeightedToken::WeightedToken(word_t &&_data, freq_t _freq) : Token(std::move(_data)), freq(_freq) {}
|
||||
|
||||
bool operator==(const WeightedToken &t1, const WeightedToken &t2) {
|
||||
return t1.data == t2.data && t1.freq == t2.freq;
|
||||
}
|
||||
|
||||
bool operator!=(const WeightedToken &t1, const WeightedToken &t2) {
|
||||
return !(t1 == t2);
|
||||
}
|
||||
|
||||
bool operator<(const WeightedToken &t1, const WeightedToken &t2) {
|
||||
return t1.freq < t2.freq;
|
||||
}
|
||||
|
||||
bool operator<=(const WeightedToken &t1, const WeightedToken &t2) {
|
||||
return t1.freq <= t2.freq;
|
||||
}
|
||||
|
||||
bool operator>(const WeightedToken &t1, const WeightedToken &t2) {
|
||||
return t1.freq > t2.freq;
|
||||
}
|
||||
|
||||
bool operator>=(const WeightedToken &t1, const WeightedToken &t2) {
|
||||
return t1.freq >= t2.freq;
|
||||
}
|
||||
|
||||
} // namespace ime::nlp
|
||||
@@ -1,51 +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.
|
||||
*/
|
||||
|
||||
#ifndef FLORISBOARD_TOKEN_H
|
||||
#define FLORISBOARD_TOKEN_H
|
||||
|
||||
#include "nlp.h"
|
||||
#include <string>
|
||||
|
||||
namespace ime::nlp {
|
||||
|
||||
class Token {
|
||||
public:
|
||||
word_t data;
|
||||
Token();
|
||||
Token(word_t &&_data);
|
||||
|
||||
friend bool operator==(const Token &t1, const Token &t2);
|
||||
friend bool operator!=(const Token &t1, const Token &t2);
|
||||
};
|
||||
|
||||
class WeightedToken : public Token {
|
||||
public:
|
||||
freq_t freq;
|
||||
WeightedToken();
|
||||
WeightedToken(word_t &&_data, freq_t _freq);
|
||||
|
||||
friend bool operator==(const WeightedToken &t1, const WeightedToken &t2);
|
||||
friend bool operator!=(const WeightedToken &t1, const WeightedToken &t2);
|
||||
friend bool operator<(const WeightedToken &t1, const WeightedToken &t2);
|
||||
friend bool operator<=(const WeightedToken &t1, const WeightedToken &t2);
|
||||
friend bool operator>(const WeightedToken &t1, const WeightedToken &t2);
|
||||
friend bool operator>=(const WeightedToken &t1, const WeightedToken &t2);
|
||||
};
|
||||
|
||||
} // namespace ime::nlp
|
||||
|
||||
#endif // FLORISBOARD_TOKEN_H
|
||||
@@ -1,10 +0,0 @@
|
||||
add_library(
|
||||
# Name
|
||||
ime-spelling
|
||||
|
||||
# Headers
|
||||
spellingdict.h
|
||||
|
||||
# Sources
|
||||
spellingdict.cpp
|
||||
)
|
||||
@@ -1,51 +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.
|
||||
*/
|
||||
|
||||
#include "spellingdict.h"
|
||||
#include "utils/log.h"
|
||||
|
||||
using namespace ime::spellcheck;
|
||||
|
||||
SpellingDict::SpellingDict(const nuspell::Dictionary& dict) : dictionary(std::make_unique<nuspell::Dictionary>(dict))
|
||||
{ }
|
||||
|
||||
SpellingDict::~SpellingDict() = default;
|
||||
|
||||
SpellingDict* SpellingDict::load(const std::string &basePath) {
|
||||
utils::start_stdout_stderr_logger("spell-floris");
|
||||
try {
|
||||
auto temp = nuspell::Dictionary::load_from_path(basePath);
|
||||
auto spellingDict = new SpellingDict(temp);
|
||||
return spellingDict;
|
||||
} catch (const nuspell::Dictionary_Loading_Error& e) {
|
||||
utils::log_error("SpellingDict.load()", e.what());
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
utils::log_error("SpellingDict.load()", "An unknown error occurred!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellingDict::spell(const std::string& word) {
|
||||
bool result = dictionary->spell(word);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> SpellingDict::suggest(const std::string &word) {
|
||||
auto result = std::vector<std::string>();
|
||||
dictionary->suggest(word, result);
|
||||
return result;
|
||||
}
|
||||
@@ -1,42 +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.
|
||||
*/
|
||||
|
||||
#ifndef FLORISBOARD_SPELLINGDICT_H
|
||||
#define FLORISBOARD_SPELLINGDICT_H
|
||||
|
||||
#include "nuspell/dictionary.hxx"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ime::spellcheck {
|
||||
|
||||
class SpellingDict {
|
||||
public:
|
||||
SpellingDict(const nuspell::Dictionary& dict);
|
||||
~SpellingDict();
|
||||
|
||||
static SpellingDict* load(const std::string& basePath);
|
||||
|
||||
bool spell(const std::string& word);
|
||||
std::vector<std::string> suggest(const std::string& word);
|
||||
|
||||
private:
|
||||
std::unique_ptr<nuspell::Dictionary> dictionary;
|
||||
};
|
||||
|
||||
} // namespace ime::spellcheck
|
||||
|
||||
#endif // FLORISBOARD_SPELLINGDICT_H
|
||||
1
app/src/main/cpp/nlp
Submodule
1
app/src/main/cpp/nlp
Submodule
Submodule app/src/main/cpp/nlp added at 9e8d49649d
@@ -1,10 +0,0 @@
|
||||
add_library(nuspell
|
||||
aff_data.cxx aff_data.hxx
|
||||
checker.cxx checker.hxx
|
||||
suggester.cxx suggester.hxx
|
||||
dictionary.cxx dictionary.hxx
|
||||
unicode.hxx
|
||||
utils.cxx utils.hxx
|
||||
structures.hxx)
|
||||
|
||||
add_library(Nuspell::nuspell ALIAS nuspell)
|
||||
@@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,173 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NUSPELL_AFF_DATA_HXX
|
||||
#define NUSPELL_AFF_DATA_HXX
|
||||
|
||||
#include "nuspell_export.h"
|
||||
#include "structures.hxx"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <unicode/locid.h>
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
class Encoding {
|
||||
std::string name;
|
||||
|
||||
NUSPELL_EXPORT auto normalize_name() -> void;
|
||||
|
||||
public:
|
||||
enum Enc_Type { SINGLEBYTE = false, UTF8 = true };
|
||||
|
||||
Encoding() = default;
|
||||
explicit Encoding(const std::string& e) : name(e) { normalize_name(); }
|
||||
explicit Encoding(std::string&& e) : name(move(e)) { normalize_name(); }
|
||||
explicit Encoding(const char* e) : name(e) { normalize_name(); }
|
||||
auto& operator=(const std::string& e)
|
||||
{
|
||||
name = e;
|
||||
normalize_name();
|
||||
return *this;
|
||||
}
|
||||
auto& operator=(std::string&& e)
|
||||
{
|
||||
name = move(e);
|
||||
normalize_name();
|
||||
return *this;
|
||||
}
|
||||
auto& operator=(const char* e)
|
||||
{
|
||||
name = e;
|
||||
normalize_name();
|
||||
return *this;
|
||||
}
|
||||
auto empty() const { return name.empty(); }
|
||||
auto& value() const { return name; }
|
||||
auto is_utf8() const { return name == "UTF-8"; }
|
||||
auto value_or_default() const -> std::string
|
||||
{
|
||||
if (name.empty())
|
||||
return "ISO8859-1";
|
||||
else
|
||||
return name;
|
||||
}
|
||||
operator Enc_Type() const { return is_utf8() ? UTF8 : SINGLEBYTE; }
|
||||
};
|
||||
|
||||
enum class Flag_Type { SINGLE_CHAR, DOUBLE_CHAR, NUMBER, UTF8 };
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Map between words and word_flags.
|
||||
*
|
||||
* Flags are stored as part of the container. Maybe for the future flags should
|
||||
* be stored elsewhere (flag aliases) and this should store pointers.
|
||||
*
|
||||
* Does not store morphological data as is low priority feature and is out of
|
||||
* scope.
|
||||
*/
|
||||
using Word_List = Hash_Multimap<std::string, Flag_Set>;
|
||||
|
||||
struct Aff_Data {
|
||||
static constexpr auto HIDDEN_HOMONYM_FLAG = char16_t(-1);
|
||||
static constexpr auto MAX_SUGGESTIONS = size_t(16);
|
||||
|
||||
// spell checking options
|
||||
Word_List words;
|
||||
Prefix_Table prefixes;
|
||||
Suffix_Table suffixes;
|
||||
|
||||
bool complex_prefixes;
|
||||
bool fullstrip;
|
||||
bool checksharps;
|
||||
bool forbid_warn;
|
||||
char16_t compound_onlyin_flag;
|
||||
char16_t circumfix_flag;
|
||||
char16_t forbiddenword_flag;
|
||||
char16_t keepcase_flag;
|
||||
char16_t need_affix_flag;
|
||||
char16_t warn_flag;
|
||||
|
||||
// compounding options
|
||||
char16_t compound_flag;
|
||||
char16_t compound_begin_flag;
|
||||
char16_t compound_last_flag;
|
||||
char16_t compound_middle_flag;
|
||||
Compound_Rule_Table compound_rules;
|
||||
|
||||
// spell checking options
|
||||
Break_Table break_table;
|
||||
Substr_Replacer input_substr_replacer;
|
||||
std::string ignored_chars;
|
||||
icu::Locale icu_locale;
|
||||
Substr_Replacer output_substr_replacer;
|
||||
|
||||
// suggestion options
|
||||
Replacement_Table replacements;
|
||||
std::vector<Similarity_Group> similarities;
|
||||
std::string keyboard_closeness;
|
||||
std::string try_chars;
|
||||
// Phonetic_Table phonetic_table;
|
||||
|
||||
char16_t nosuggest_flag;
|
||||
char16_t substandard_flag;
|
||||
unsigned short max_compound_suggestions;
|
||||
unsigned short max_ngram_suggestions;
|
||||
unsigned short max_diff_factor;
|
||||
bool only_max_diff;
|
||||
bool no_split_suggestions;
|
||||
bool suggest_with_dots;
|
||||
|
||||
// compounding options
|
||||
unsigned short compound_min_length;
|
||||
unsigned short compound_max_word_count;
|
||||
char16_t compound_permit_flag;
|
||||
char16_t compound_forbid_flag;
|
||||
char16_t compound_root_flag;
|
||||
char16_t compound_force_uppercase;
|
||||
bool compound_more_suffixes;
|
||||
bool compound_check_duplicate;
|
||||
bool compound_check_rep;
|
||||
bool compound_check_case;
|
||||
bool compound_check_triple;
|
||||
bool compound_simplified_triple;
|
||||
bool compound_syllable_num;
|
||||
unsigned short compound_syllable_max;
|
||||
std::string compound_syllable_vowels;
|
||||
std::vector<Compound_Pattern> compound_patterns;
|
||||
|
||||
// data members used only while parsing
|
||||
Flag_Type flag_type;
|
||||
Encoding encoding;
|
||||
std::vector<Flag_Set> flag_aliases;
|
||||
std::string wordchars; // deprecated?
|
||||
|
||||
auto parse_aff(std::istream& in) -> bool;
|
||||
auto parse_dic(std::istream& in) -> bool;
|
||||
auto parse_aff_dic(std::istream& aff, std::istream& dic)
|
||||
{
|
||||
if (parse_aff(aff))
|
||||
return parse_dic(dic);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
#endif // NUSPELL_AFF_DATA_HXX
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,352 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NUSPELL_CHECKER_HXX
|
||||
#define NUSPELL_CHECKER_HXX
|
||||
|
||||
#include "aff_data.hxx"
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
enum Affixing_Mode {
|
||||
FULL_WORD,
|
||||
AT_COMPOUND_BEGIN,
|
||||
AT_COMPOUND_END,
|
||||
AT_COMPOUND_MIDDLE
|
||||
};
|
||||
|
||||
struct Affixing_Result_Base {
|
||||
Word_List::const_pointer root_word = {};
|
||||
|
||||
operator Word_List::const_pointer() const { return root_word; }
|
||||
auto& operator*() const { return *root_word; }
|
||||
auto operator->() const { return root_word; }
|
||||
};
|
||||
|
||||
template <class T1 = void, class T2 = void>
|
||||
struct Affixing_Result : Affixing_Result_Base {
|
||||
const T1* a = {};
|
||||
const T2* b = {};
|
||||
|
||||
Affixing_Result() = default;
|
||||
Affixing_Result(Word_List::const_reference r, const T1& a, const T2& b)
|
||||
: Affixing_Result_Base{&r}, a{&a}, b{&b}
|
||||
{
|
||||
}
|
||||
};
|
||||
template <class T1>
|
||||
struct Affixing_Result<T1, void> : Affixing_Result_Base {
|
||||
const T1* a = {};
|
||||
|
||||
Affixing_Result() = default;
|
||||
Affixing_Result(Word_List::const_reference r, const T1& a)
|
||||
: Affixing_Result_Base{&r}, a{&a}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Affixing_Result<void, void> : Affixing_Result_Base {
|
||||
Affixing_Result() = default;
|
||||
Affixing_Result(Word_List::const_reference r) : Affixing_Result_Base{&r}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Compounding_Result {
|
||||
Word_List::const_pointer word_entry = {};
|
||||
unsigned char num_words_modifier = {};
|
||||
signed char num_syllable_modifier = {};
|
||||
bool affixed_and_modified = {}; /**< non-zero affix */
|
||||
operator Word_List::const_pointer() const { return word_entry; }
|
||||
auto& operator*() const { return *word_entry; }
|
||||
auto operator->() const { return word_entry; }
|
||||
};
|
||||
|
||||
struct Checker : public Aff_Data {
|
||||
enum Forceucase : bool {
|
||||
FORBID_BAD_FORCEUCASE = false,
|
||||
ALLOW_BAD_FORCEUCASE = true
|
||||
};
|
||||
|
||||
enum Hidden_Homonym : bool {
|
||||
ACCEPT_HIDDEN_HOMONYM = false,
|
||||
SKIP_HIDDEN_HOMONYM = true
|
||||
};
|
||||
Checker()
|
||||
: Aff_Data() // we explicity do value init so content is zeroed
|
||||
{
|
||||
}
|
||||
auto spell_priv(std::string& s) const -> bool;
|
||||
auto spell_break(std::string& s, size_t depth = 0) const -> bool;
|
||||
auto spell_casing(std::string& s) const -> const Flag_Set*;
|
||||
auto spell_casing_upper(std::string& s) const -> const Flag_Set*;
|
||||
auto spell_casing_title(std::string& s) const -> const Flag_Set*;
|
||||
auto spell_sharps(std::string& base, size_t n_pos = 0, size_t n = 0,
|
||||
size_t rep = 0) const -> const Flag_Set*;
|
||||
|
||||
auto check_word(std::string& s, Forceucase allow_bad_forceucase = {},
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> const Flag_Set*;
|
||||
auto check_simple_word(std::string& word,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> const Flag_Set*;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto affix_NOT_valid(const Prefix& a) const;
|
||||
template <Affixing_Mode m>
|
||||
auto affix_NOT_valid(const Suffix& a) const;
|
||||
template <Affixing_Mode m, class AffixT>
|
||||
auto outer_affix_NOT_valid(const AffixT& a) const;
|
||||
template <class AffixT>
|
||||
auto is_circumfix(const AffixT& a) const;
|
||||
template <Affixing_Mode m>
|
||||
auto is_valid_inside_compound(const Flag_Set& flags) const;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_prefix_only(std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Prefix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_suffix_only(std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Suffix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto
|
||||
strip_prefix_then_suffix(std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Suffix, Prefix>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_pfx_then_sfx_2(const Prefix& pe, std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<Suffix, Prefix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto
|
||||
strip_suffix_then_prefix(std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Prefix, Suffix>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_sfx_then_pfx_2(const Suffix& se, std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<Prefix, Suffix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_prefix_then_suffix_commutative(
|
||||
std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Suffix, Prefix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_pfx_then_sfx_comm_2(const Prefix& pe, std::string& word,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<Suffix, Prefix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto
|
||||
strip_suffix_then_suffix(std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Suffix, Suffix>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_sfx_then_sfx_2(const Suffix& se1, std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<Suffix, Suffix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto
|
||||
strip_prefix_then_prefix(std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<Prefix, Prefix>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_pfx_then_pfx_2(const Prefix& pe1, std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<Prefix, Prefix>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_prefix_then_2_suffixes(
|
||||
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_pfx_2_sfx_3(const Prefix& pe1, const Suffix& se1,
|
||||
std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_suffix_prefix_suffix(
|
||||
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_s_p_s_3(const Suffix& se1, const Prefix& pe1,
|
||||
std::string& word,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_2_suffixes_then_prefix(
|
||||
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_2_sfx_pfx_3(const Suffix& se1, const Suffix& se2,
|
||||
std::string& word,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_suffix_then_2_prefixes(
|
||||
std::string& s, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_sfx_2_pfx_3(const Suffix& se1, const Prefix& pe1,
|
||||
std::string& s,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_prefix_suffix_prefix(
|
||||
std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_p_s_p_3(const Prefix& pe1, const Suffix& se1,
|
||||
std::string& word,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m = FULL_WORD>
|
||||
auto strip_2_prefixes_then_suffix(
|
||||
std::string& word, Hidden_Homonym skip_hidden_homonym = {}) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto strip_2_pfx_sfx_3(const Prefix& pe1, const Prefix& pe2,
|
||||
std::string& word,
|
||||
Hidden_Homonym skip_hidden_homonym) const
|
||||
-> Affixing_Result<>;
|
||||
|
||||
auto check_compound(std::string& word,
|
||||
Forceucase allow_bad_forceucase) const
|
||||
-> Compounding_Result;
|
||||
|
||||
template <Affixing_Mode m = AT_COMPOUND_BEGIN>
|
||||
auto check_compound(std::string& word, size_t start_pos,
|
||||
size_t num_part, std::string& part,
|
||||
Forceucase allow_bad_forceucase) const
|
||||
-> Compounding_Result;
|
||||
|
||||
template <Affixing_Mode m = AT_COMPOUND_BEGIN>
|
||||
auto check_compound_classic(std::string& word, size_t start_pos,
|
||||
size_t i, size_t num_part,
|
||||
std::string& part,
|
||||
Forceucase allow_bad_forceucase) const
|
||||
-> Compounding_Result;
|
||||
|
||||
template <Affixing_Mode m = AT_COMPOUND_BEGIN>
|
||||
auto check_compound_with_pattern_replacements(
|
||||
std::string& word, size_t start_pos, size_t i, size_t num_part,
|
||||
std::string& part, Forceucase allow_bad_forceucase) const
|
||||
-> Compounding_Result;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto check_word_in_compound(std::string& s) const -> Compounding_Result;
|
||||
|
||||
auto calc_num_words_modifier(const Prefix& pfx) const -> unsigned char;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto calc_syllable_modifier(Word_List::const_reference we) const
|
||||
-> signed char;
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto calc_syllable_modifier(Word_List::const_reference we,
|
||||
const Suffix& sfx) const -> signed char;
|
||||
|
||||
auto count_syllables(std::string_view word) const -> size_t;
|
||||
|
||||
auto check_compound_with_rules(std::string& word,
|
||||
std::vector<const Flag_Set*>& words_data,
|
||||
size_t start_pos, std::string& part,
|
||||
Forceucase allow_bad_forceucase) const
|
||||
|
||||
-> Compounding_Result;
|
||||
auto is_rep_similar(std::string& word) const -> bool;
|
||||
};
|
||||
|
||||
template <Affixing_Mode m>
|
||||
auto Checker::affix_NOT_valid(const Prefix& e) const
|
||||
{
|
||||
if (m == FULL_WORD && e.cont_flags.contains(compound_onlyin_flag))
|
||||
return true;
|
||||
if (m == AT_COMPOUND_END &&
|
||||
!e.cont_flags.contains(compound_permit_flag))
|
||||
return true;
|
||||
if (m != FULL_WORD && e.cont_flags.contains(compound_forbid_flag))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
template <Affixing_Mode m>
|
||||
auto Checker::affix_NOT_valid(const Suffix& e) const
|
||||
{
|
||||
if (m == FULL_WORD && e.cont_flags.contains(compound_onlyin_flag))
|
||||
return true;
|
||||
if (m == AT_COMPOUND_BEGIN &&
|
||||
!e.cont_flags.contains(compound_permit_flag))
|
||||
return true;
|
||||
if (m != FULL_WORD && e.cont_flags.contains(compound_forbid_flag))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
template <Affixing_Mode m, class AffixT>
|
||||
auto Checker::outer_affix_NOT_valid(const AffixT& e) const
|
||||
{
|
||||
if (affix_NOT_valid<m>(e))
|
||||
return true;
|
||||
if (e.cont_flags.contains(need_affix_flag))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
template <class AffixT>
|
||||
auto Checker::is_circumfix(const AffixT& a) const
|
||||
{
|
||||
return a.cont_flags.contains(circumfix_flag);
|
||||
}
|
||||
|
||||
template <class AffixInner, class AffixOuter>
|
||||
auto cross_valid_inner_outer(const AffixInner& inner, const AffixOuter& outer)
|
||||
{
|
||||
return inner.cont_flags.contains(outer.flag);
|
||||
}
|
||||
|
||||
template <class Affix>
|
||||
auto cross_valid_inner_outer(const Flag_Set& word_flags, const Affix& afx)
|
||||
{
|
||||
return word_flags.contains(afx.flag);
|
||||
}
|
||||
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
#endif // NUSPELL_CHECKER_HXX
|
||||
@@ -1 +0,0 @@
|
||||
clang-format -style=file -i *.[ch]xx
|
||||
@@ -1,115 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dictionary.hxx"
|
||||
#include "utils.hxx"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
Dictionary::Dictionary(std::istream& aff, std::istream& dic)
|
||||
{
|
||||
if (!parse_aff_dic(aff, dic))
|
||||
throw Dictionary_Loading_Error("error parsing");
|
||||
}
|
||||
|
||||
Dictionary::Dictionary() = default;
|
||||
|
||||
/**
|
||||
* @brief Create a dictionary from opened files as iostreams
|
||||
*
|
||||
* Prefer using load_from_path(). Use this if you have a specific use case,
|
||||
* like when .aff and .dic are in-memory buffers istringstream.
|
||||
*
|
||||
* @param aff The iostream of the .aff file
|
||||
* @param dic The iostream of the .dic file
|
||||
* @return Dictionary object
|
||||
* @throws Dictionary_Loading_Error on error
|
||||
*/
|
||||
auto Dictionary::load_from_aff_dic(std::istream& aff, std::istream& dic)
|
||||
-> Dictionary
|
||||
{
|
||||
return Dictionary(aff, dic);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a dictionary from files
|
||||
* @param file_path_without_extension path *without* extensions (without .dic or
|
||||
* .aff)
|
||||
* @return Dictionary object
|
||||
* @throws Dictionary_Loading_Error on error
|
||||
*/
|
||||
auto Dictionary::load_from_path(const std::string& file_path_without_extension)
|
||||
-> Dictionary
|
||||
{
|
||||
auto path = file_path_without_extension;
|
||||
path += ".aff";
|
||||
std::ifstream aff_file(path);
|
||||
if (aff_file.fail()) {
|
||||
auto err = "Aff file " + path + " not found";
|
||||
throw Dictionary_Loading_Error(err);
|
||||
}
|
||||
path.replace(path.size() - 3, 3, "dic");
|
||||
std::ifstream dic_file(path);
|
||||
if (dic_file.fail()) {
|
||||
auto err = "Dic file " + path + " not found";
|
||||
throw Dictionary_Loading_Error(err);
|
||||
}
|
||||
return load_from_aff_dic(aff_file, dic_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a given word is correct
|
||||
* @param word any word
|
||||
* @return true if correct, false otherwise
|
||||
*/
|
||||
auto Dictionary::spell(std::string_view word) const -> bool
|
||||
{
|
||||
auto ok_enc = validate_utf8(word);
|
||||
if (unlikely(word.size() > 360))
|
||||
return false;
|
||||
if (unlikely(!ok_enc))
|
||||
return false;
|
||||
auto word_buf = string(word);
|
||||
return spell_priv(word_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suggests correct words for a given incorrect word
|
||||
* @param[in] word incorrect word
|
||||
* @param[out] out this object will be populated with the suggestions
|
||||
*/
|
||||
auto Dictionary::suggest(std::string_view word,
|
||||
std::vector<std::string>& out) const -> void
|
||||
{
|
||||
out.clear();
|
||||
auto ok_enc = validate_utf8(word);
|
||||
if (unlikely(word.size() > 360))
|
||||
return;
|
||||
if (unlikely(!ok_enc))
|
||||
return;
|
||||
suggest_priv(word, out);
|
||||
}
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
@@ -1,59 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Dictionary spelling.
|
||||
*/
|
||||
|
||||
#ifndef NUSPELL_DICTIONARY_HXX
|
||||
#define NUSPELL_DICTIONARY_HXX
|
||||
|
||||
#include "suggester.hxx"
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
/**
|
||||
* @brief The only important public exception
|
||||
*/
|
||||
class Dictionary_Loading_Error : public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The only important public class
|
||||
*/
|
||||
class NUSPELL_EXPORT Dictionary : private Suggester {
|
||||
Dictionary(std::istream& aff, std::istream& dic);
|
||||
|
||||
public:
|
||||
Dictionary();
|
||||
auto static load_from_aff_dic(std::istream& aff, std::istream& dic)
|
||||
-> Dictionary;
|
||||
auto static load_from_path(
|
||||
const std::string& file_path_without_extension) -> Dictionary;
|
||||
auto spell(std::string_view word) const -> bool;
|
||||
auto suggest(std::string_view word, std::vector<std::string>& out) const
|
||||
-> void;
|
||||
};
|
||||
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
#endif // NUSPELL_DICTIONARY_HXX
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef NUSPELL_EXPORT_H
|
||||
#define NUSPELL_EXPORT_H
|
||||
|
||||
#ifdef NUSPELL_STATIC_DEFINE
|
||||
# define NUSPELL_EXPORT
|
||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||
# ifdef nuspell_EXPORTS // Define this only when building Nuspell as DLL on Windows, not when using the DLL.
|
||||
# define NUSPELL_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define NUSPELL_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#elif __GNUC__ >= 4
|
||||
# define NUSPELL_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
# define NUSPELL_EXPORT
|
||||
#endif
|
||||
|
||||
#endif /* NUSPELL_EXPORT_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,97 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NUSPELL_SUGGESTER_HXX
|
||||
#define NUSPELL_SUGGESTER_HXX
|
||||
|
||||
#include "checker.hxx"
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
struct NUSPELL_EXPORT Suggester : public Checker {
|
||||
|
||||
enum High_Quality_Sugs : bool {
|
||||
ALL_LOW_QUALITY_SUGS = false,
|
||||
HAS_HIGH_QUALITY_SUGS = true
|
||||
};
|
||||
|
||||
auto suggest_priv(std::string_view input_word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto suggest_low(std::string& word, List_Strings& out) const
|
||||
-> High_Quality_Sugs;
|
||||
|
||||
auto add_sug_if_correct(std::string& word, List_Strings& out) const
|
||||
-> bool;
|
||||
|
||||
auto uppercase_suggest(const std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto rep_suggest(std::string& word, List_Strings& out) const -> void;
|
||||
|
||||
auto try_rep_suggestion(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto max_attempts_for_long_alogs(std::string_view word) const -> size_t;
|
||||
|
||||
auto map_suggest(std::string& word, List_Strings& out) const -> void;
|
||||
|
||||
auto map_suggest(std::string& word, List_Strings& out, size_t i,
|
||||
size_t& remaining_attempts) const -> void;
|
||||
|
||||
auto adjacent_swap_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto distant_swap_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto keyboard_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto extra_char_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto forgotten_char_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto move_char_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto bad_char_suggest(std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto doubled_two_chars_suggest(std::string& word,
|
||||
List_Strings& out) const -> void;
|
||||
|
||||
auto two_words_suggest(const std::string& word, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto ngram_suggest(const std::string& word_u8, List_Strings& out) const
|
||||
-> void;
|
||||
|
||||
auto expand_root_word_for_ngram(Word_List::const_reference root,
|
||||
std::string_view wrong,
|
||||
List_Strings& expanded_list,
|
||||
std::vector<bool>& cross_affix) const
|
||||
-> void;
|
||||
};
|
||||
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
#endif // NUSPELL_SUGGESTER_HXX
|
||||
@@ -1,383 +0,0 @@
|
||||
/* Copyright 2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef NUSPELL_UNICODE_HXX
|
||||
#define NUSPELL_UNICODE_HXX
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unicode/utf16.h>
|
||||
#include <unicode/utf8.h>
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
// UTF-8, work on malformed
|
||||
|
||||
inline constexpr auto u8_max_cp_length = U8_MAX_LENGTH;
|
||||
|
||||
auto inline u8_is_cp_error(int32_t cp) -> bool { return cp < 0; }
|
||||
|
||||
template <class Range>
|
||||
auto u8_advance_cp(const Range& str, size_t& i, int32_t& cp) -> void
|
||||
{
|
||||
using std::size, std::data;
|
||||
#if U_ICU_VERSION_MAJOR_NUM <= 60
|
||||
auto s_ptr = data(str);
|
||||
int32_t idx = i;
|
||||
int32_t len = size(str);
|
||||
U8_NEXT(s_ptr, idx, len, cp);
|
||||
i = idx;
|
||||
#else
|
||||
auto len = size(str);
|
||||
U8_NEXT(str, i, len, cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u8_advance_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
using std::size;
|
||||
auto len = size(str);
|
||||
U8_FWD_1(str, i, len);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u8_reverse_cp(const Range& str, size_t& i, int32_t& cp) -> void
|
||||
{
|
||||
using std::size, std::data;
|
||||
auto ptr = data(str);
|
||||
int32_t idx = i;
|
||||
U8_PREV(ptr, 0, idx, cp);
|
||||
i = idx;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u8_reverse_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
using std::size, std::data;
|
||||
auto ptr = data(str);
|
||||
int32_t idx = i;
|
||||
U8_BACK_1(ptr, 0, idx);
|
||||
i = idx;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u8_write_cp_and_advance(Range& buf, size_t& i, int32_t cp, bool& error)
|
||||
-> void
|
||||
{
|
||||
using std::size, std::data;
|
||||
#if U_ICU_VERSION_MAJOR_NUM <= 60
|
||||
auto ptr = data(buf);
|
||||
int32_t idx = i;
|
||||
int32_t len = size(buf);
|
||||
U8_APPEND(buf, idx, len, cp, error);
|
||||
i = idx;
|
||||
#else
|
||||
auto len = size(buf);
|
||||
U8_APPEND(buf, i, len, cp, error);
|
||||
#endif
|
||||
}
|
||||
|
||||
// UTF-8, valid
|
||||
|
||||
template <class Range>
|
||||
auto valid_u8_advance_cp(const Range& str, size_t& i, char32_t& cp) -> void
|
||||
{
|
||||
U8_NEXT_UNSAFE(str, i, cp);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u8_advance_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
U8_FWD_1_UNSAFE(str, i);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u8_reverse_cp(const Range& str, size_t& i, char32_t& cp) -> void
|
||||
{
|
||||
U8_PREV_UNSAFE(str, i, cp);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u8_reverse_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
U8_BACK_1_UNSAFE(str, i);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u8_write_cp_and_advance(Range& buf, size_t& i, char32_t cp) -> void
|
||||
{
|
||||
U8_APPEND_UNSAFE(buf, i, cp);
|
||||
}
|
||||
|
||||
// UTF-16, work on malformed
|
||||
|
||||
inline constexpr auto u16_max_cp_length = U16_MAX_LENGTH;
|
||||
|
||||
auto inline u16_is_cp_error(int32_t cp) -> bool { return U_IS_SURROGATE(cp); }
|
||||
|
||||
template <class Range>
|
||||
auto u16_advance_cp(const Range& str, size_t& i, int32_t& cp) -> void
|
||||
{
|
||||
using std::size;
|
||||
auto len = size(str);
|
||||
U16_NEXT(str, i, len, cp);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u16_advance_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
using std::size;
|
||||
auto len = size(str);
|
||||
U16_FWD_1(str, i, len);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u16_reverse_cp(const Range& str, size_t& i, int32_t& cp) -> void
|
||||
{
|
||||
U16_PREV(str, 0, i, cp);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u16_reverse_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
U16_BACK_1(str, 0, i);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto u16_write_cp_and_advance(Range& buf, size_t& i, int32_t cp, bool& error)
|
||||
-> void
|
||||
{
|
||||
using std::size;
|
||||
auto len = size(buf);
|
||||
U16_APPEND(buf, i, len, cp, error);
|
||||
}
|
||||
|
||||
// UTF-16, valid
|
||||
|
||||
template <class Range>
|
||||
auto valid_u16_advance_cp(const Range& str, size_t& i, char32_t& cp) -> void
|
||||
{
|
||||
U16_NEXT_UNSAFE(str, i, cp);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u16_advance_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
U16_FWD_1_UNSAFE(str, i);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u16_reverse_cp(const Range& str, size_t& i, char32_t& cp) -> void
|
||||
{
|
||||
U16_PREV_UNSAFE(str, i, cp);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u16_reverse_index(const Range& str, size_t& i) -> void
|
||||
{
|
||||
U16_BACK_1_UNSAFE(str, i);
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
auto valid_u16_write_cp_and_advance(Range& buf, size_t& i, char32_t cp) -> void
|
||||
{
|
||||
U16_APPEND_UNSAFE(buf, i, cp);
|
||||
}
|
||||
|
||||
// higer level funcs
|
||||
|
||||
struct U8_CP_Pos {
|
||||
size_t begin_i = 0;
|
||||
size_t end_i = begin_i;
|
||||
};
|
||||
|
||||
class U8_Encoded_CP {
|
||||
char d[u8_max_cp_length];
|
||||
int sz;
|
||||
|
||||
public:
|
||||
explicit U8_Encoded_CP(std::string_view str, U8_CP_Pos pos)
|
||||
: sz(pos.end_i - pos.begin_i)
|
||||
{
|
||||
auto i = sz;
|
||||
auto j = pos.end_i;
|
||||
auto max_len = 4;
|
||||
do {
|
||||
d[--i] = str[--j];
|
||||
} while (i && --max_len);
|
||||
}
|
||||
U8_Encoded_CP(char32_t cp)
|
||||
{
|
||||
size_t z = 0;
|
||||
valid_u8_write_cp_and_advance(d, z, cp);
|
||||
sz = z;
|
||||
}
|
||||
auto size() const noexcept -> size_t { return sz; }
|
||||
auto data() const noexcept -> const char* { return d; }
|
||||
operator std::string_view() const noexcept
|
||||
{
|
||||
return std::string_view(data(), size());
|
||||
}
|
||||
auto copy_to(std::string& str, size_t j) const
|
||||
{
|
||||
auto i = sz;
|
||||
j += sz;
|
||||
auto max_len = 4;
|
||||
do {
|
||||
str[--j] = d[--i];
|
||||
} while (i && --max_len);
|
||||
}
|
||||
};
|
||||
|
||||
auto inline u8_swap_adjacent_cp(std::string& str, size_t i1, size_t i2,
|
||||
size_t i3) -> size_t
|
||||
{
|
||||
auto cp1 = U8_Encoded_CP(str, {i1, i2});
|
||||
auto cp2 = U8_Encoded_CP(str, {i2, i3});
|
||||
auto new_i2 = i1 + std::size(cp2);
|
||||
cp1.copy_to(str, new_i2);
|
||||
cp2.copy_to(str, i1);
|
||||
return new_i2;
|
||||
}
|
||||
|
||||
auto inline u8_swap_cp(std::string& str, U8_CP_Pos pos1, U8_CP_Pos pos2)
|
||||
-> std::pair<size_t, size_t>
|
||||
{
|
||||
using std::size;
|
||||
auto cp1 = U8_Encoded_CP(str, pos1);
|
||||
auto cp2 = U8_Encoded_CP(str, pos2);
|
||||
auto new_p1_end_i = pos1.begin_i + size(cp2);
|
||||
auto new_p2_begin_i = pos2.end_i - size(cp1);
|
||||
std::char_traits<char>::move(&str[new_p1_end_i], &str[pos1.end_i],
|
||||
pos2.begin_i - pos1.end_i);
|
||||
cp2.copy_to(str, pos1.begin_i);
|
||||
cp1.copy_to(str, new_p2_begin_i);
|
||||
return {new_p1_end_i, new_p2_begin_i};
|
||||
}
|
||||
|
||||
// bellow go func without out-parametars
|
||||
|
||||
// UTF-8, can be malformed, no out-parametars
|
||||
|
||||
struct Idx_And_Next_CP {
|
||||
size_t end_i;
|
||||
int32_t cp;
|
||||
};
|
||||
|
||||
struct Idx_And_Prev_CP {
|
||||
size_t begin_i;
|
||||
int32_t cp;
|
||||
};
|
||||
|
||||
struct Write_CP_Idx_and_Error {
|
||||
size_t end_i;
|
||||
bool error;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto u8_next_cp(const Range& str, size_t i) -> Idx_And_Next_CP
|
||||
{
|
||||
int32_t cp;
|
||||
u8_advance_cp(str, i, cp);
|
||||
return {i, cp};
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto u8_next_index(const Range& str, size_t i) -> size_t
|
||||
{
|
||||
u8_advance_index(str, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto u8_prev_cp(const Range& str, size_t i) -> Idx_And_Prev_CP
|
||||
{
|
||||
int32_t cp;
|
||||
u8_reverse_cp(str, i, cp);
|
||||
return {i, cp};
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto u8_prev_index(const Range& str, size_t i) -> size_t
|
||||
{
|
||||
u8_reverse_index(str, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto u8_write_cp(Range& buf, size_t i, int32_t cp)
|
||||
-> Write_CP_Idx_and_Error
|
||||
{
|
||||
bool err;
|
||||
u8_write_cp_and_advance(buf, i, cp, err);
|
||||
return {i, err};
|
||||
}
|
||||
|
||||
// UTF-8, valid, no out-parametars
|
||||
|
||||
struct Idx_And_Next_CP_Valid {
|
||||
size_t end_i;
|
||||
char32_t cp;
|
||||
};
|
||||
|
||||
struct Idx_And_Prev_CP_Valid {
|
||||
size_t begin_i;
|
||||
char32_t cp;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto valid_u8_next_cp(const Range& str, size_t i)
|
||||
-> Idx_And_Next_CP_Valid
|
||||
{
|
||||
char32_t cp;
|
||||
valid_u8_advance_cp(str, i, cp);
|
||||
return {i, cp};
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto valid_u8_next_index(const Range& str, size_t i) -> size_t
|
||||
{
|
||||
valid_u8_advance_index(str, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto valid_u8_prev_cp(const Range& str, size_t i)
|
||||
-> Idx_And_Prev_CP_Valid
|
||||
{
|
||||
char32_t cp;
|
||||
valid_u8_reverse_cp(str, i, cp);
|
||||
return {i, cp};
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto valid_u8_prev_index(const Range& str, size_t i) -> size_t
|
||||
{
|
||||
valid_u8_reverse_index(str, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class Range>
|
||||
[[nodiscard]] auto valid_u8_write_cp(Range& buf, size_t i, int32_t cp) -> size_t
|
||||
{
|
||||
valid_u8_write_cp_and_advance(buf, i, cp);
|
||||
return i;
|
||||
}
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
#endif // NUSPELL_UNICODE_HXX
|
||||
@@ -1,465 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils.hxx"
|
||||
#include "unicode.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include <unicode/uchar.h>
|
||||
#include <unicode/ucnv.h>
|
||||
#include <unicode/unistr.h>
|
||||
#include <unicode/ustring.h>
|
||||
|
||||
#if ' ' != 32 || '.' != 46 || 'A' != 65 || 'Z' != 90 || 'a' != 97 || 'z' != 122
|
||||
#error "Basic execution character set is not ASCII"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
template <class SepT>
|
||||
static auto& split_on_any_of_low(std::string_view s, const SepT& sep,
|
||||
std::vector<std::string>& out)
|
||||
{
|
||||
size_t i1 = 0;
|
||||
size_t i2;
|
||||
do {
|
||||
i2 = s.find_first_of(sep, i1);
|
||||
out.emplace_back(s.substr(i1, i2 - i1));
|
||||
i1 = i2 + 1; // we can only add +1 if separator is single char.
|
||||
|
||||
// i2 gets s.npos after the last separator.
|
||||
// Length of i2-i1 will always go past the end. That is defined.
|
||||
} while (i2 != s.npos);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Splits string on single char seperator.
|
||||
*
|
||||
* Consecutive separators are treated as separate and will emit empty strings.
|
||||
*
|
||||
* @param s string to split.
|
||||
* @param sep char that acts as separator to split on.
|
||||
* @param out vector where separated strings are appended.
|
||||
* @return @p out.
|
||||
*/
|
||||
auto split(std::string_view s, char sep, std::vector<std::string>& out)
|
||||
-> std::vector<std::string>&
|
||||
{
|
||||
return split_on_any_of_low(s, sep, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Splits string on set of single char seperators.
|
||||
*
|
||||
* Consecutive separators are treated as separate and will emit empty strings.
|
||||
*
|
||||
* @param s string to split.
|
||||
* @param sep seperator(s) to split on.
|
||||
* @param out vector where separated strings are appended.
|
||||
* @return @p out.
|
||||
*/
|
||||
auto split_on_any_of(std::string_view s, const char* sep,
|
||||
std::vector<std::string>& out) -> std::vector<std::string>&
|
||||
{
|
||||
return split_on_any_of_low(s, sep, out);
|
||||
}
|
||||
|
||||
auto utf32_to_utf8(std::u32string_view in, std::string& out) -> void
|
||||
{
|
||||
out.clear();
|
||||
for (size_t i = 0; i != size(in); ++i) {
|
||||
auto cp = in[i];
|
||||
auto enc_cp = U8_Encoded_CP(cp);
|
||||
out += enc_cp;
|
||||
}
|
||||
}
|
||||
auto utf32_to_utf8(std::u32string_view in) -> std::string
|
||||
{
|
||||
auto out = string();
|
||||
utf32_to_utf8(in, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
auto valid_utf8_to_32(std::string_view in, std::u32string& out) -> void
|
||||
{
|
||||
out.clear();
|
||||
for (size_t i = 0; i != size(in);) {
|
||||
char32_t cp;
|
||||
valid_u8_advance_cp(in, i, cp);
|
||||
out.push_back(cp);
|
||||
}
|
||||
}
|
||||
auto valid_utf8_to_32(std::string_view in) -> std::u32string
|
||||
{
|
||||
auto out = u32string();
|
||||
valid_utf8_to_32(in, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
auto utf8_to_16(std::string_view in) -> std::u16string
|
||||
{
|
||||
auto out = u16string();
|
||||
utf8_to_16(in, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
bool utf8_to_16(std::string_view in, std::u16string& out)
|
||||
{
|
||||
int32_t len;
|
||||
auto err = U_ZERO_ERROR;
|
||||
u_strFromUTF8(data(out), size(out), &len, data(in), size(in), &err);
|
||||
out.resize(len);
|
||||
if (err == U_BUFFER_OVERFLOW_ERROR) {
|
||||
err = U_ZERO_ERROR;
|
||||
u_strFromUTF8(data(out), size(out), &len, data(in), size(in),
|
||||
&err);
|
||||
}
|
||||
if (U_SUCCESS(err))
|
||||
return true;
|
||||
out.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validate_utf8(string_view s)
|
||||
{
|
||||
auto err = U_ZERO_ERROR;
|
||||
u_strFromUTF8(nullptr, 0, nullptr, data(s), size(s), &err);
|
||||
if (err == U_INVALID_CHAR_FOUND)
|
||||
return false;
|
||||
return err == U_BUFFER_OVERFLOW_ERROR || U_SUCCESS(err);
|
||||
}
|
||||
|
||||
auto static is_ascii(char c) -> bool
|
||||
{
|
||||
return static_cast<unsigned char>(c) <= 127;
|
||||
}
|
||||
|
||||
auto is_all_ascii(std::string_view s) -> bool
|
||||
{
|
||||
return all_of(begin(s), end(s), is_ascii);
|
||||
}
|
||||
|
||||
auto static widen_latin1(char c) -> char16_t
|
||||
{
|
||||
return static_cast<unsigned char>(c);
|
||||
}
|
||||
|
||||
auto latin1_to_ucs2(std::string_view s) -> std::u16string
|
||||
{
|
||||
u16string ret;
|
||||
latin1_to_ucs2(s, ret);
|
||||
return ret;
|
||||
}
|
||||
auto latin1_to_ucs2(std::string_view s, std::u16string& out) -> void
|
||||
{
|
||||
out.resize(s.size());
|
||||
transform(begin(s), end(s), begin(out), widen_latin1);
|
||||
}
|
||||
|
||||
auto static is_surrogate_pair(char16_t c) -> bool
|
||||
{
|
||||
return 0xD800 <= c && c <= 0xDFFF;
|
||||
}
|
||||
auto is_all_bmp(std::u16string_view s) -> bool
|
||||
{
|
||||
return none_of(begin(s), end(s), is_surrogate_pair);
|
||||
}
|
||||
|
||||
auto to_upper_ascii(std::string& s) -> void
|
||||
{
|
||||
auto& char_type = use_facet<ctype<char>>(locale::classic());
|
||||
char_type.toupper(begin_ptr(s), end_ptr(s));
|
||||
}
|
||||
|
||||
auto static utf32_to_icu(u32string_view in) -> icu::UnicodeString
|
||||
{
|
||||
static_assert(sizeof(UChar32) == sizeof(char32_t));
|
||||
return icu::UnicodeString::fromUTF32(
|
||||
reinterpret_cast<const UChar32*>(in.data()), in.size());
|
||||
}
|
||||
auto static icu_to_utf32(const icu::UnicodeString& in, std::u32string& out)
|
||||
-> bool
|
||||
{
|
||||
out.resize(in.length());
|
||||
auto err = U_ZERO_ERROR;
|
||||
auto len =
|
||||
in.toUTF32(reinterpret_cast<UChar32*>(out.data()), out.size(), err);
|
||||
if (U_SUCCESS(err)) {
|
||||
out.erase(len);
|
||||
return true;
|
||||
}
|
||||
out.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto to_upper(std::string_view in, const icu::Locale& loc) -> std::string
|
||||
{
|
||||
auto out = std::string();
|
||||
to_upper(in, loc, out);
|
||||
return out;
|
||||
}
|
||||
auto to_title(std::string_view in, const icu::Locale& loc) -> std::string
|
||||
{
|
||||
auto out = std::string();
|
||||
to_title(in, loc, out);
|
||||
return out;
|
||||
}
|
||||
auto to_lower(std::string_view in, const icu::Locale& loc) -> std::string
|
||||
{
|
||||
auto out = std::string();
|
||||
to_lower(in, loc, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
auto to_upper(string_view in, const icu::Locale& loc, string& out) -> void
|
||||
{
|
||||
auto sp = icu::StringPiece(data(in), size(in));
|
||||
auto us = icu::UnicodeString::fromUTF8(sp);
|
||||
us.toUpper(loc);
|
||||
out.clear();
|
||||
us.toUTF8String(out);
|
||||
}
|
||||
auto to_title(string_view in, const icu::Locale& loc, string& out) -> void
|
||||
{
|
||||
auto sp = icu::StringPiece(data(in), size(in));
|
||||
auto us = icu::UnicodeString::fromUTF8(sp);
|
||||
us.toTitle(nullptr, loc);
|
||||
out.clear();
|
||||
us.toUTF8String(out);
|
||||
}
|
||||
auto to_lower(u32string_view in, const icu::Locale& loc, u32string& out) -> void
|
||||
{
|
||||
auto us = utf32_to_icu(in);
|
||||
us.toLower(loc);
|
||||
icu_to_utf32(us, out);
|
||||
}
|
||||
auto to_lower(string_view in, const icu::Locale& loc, string& out) -> void
|
||||
{
|
||||
auto sp = icu::StringPiece(data(in), size(in));
|
||||
auto us = icu::UnicodeString::fromUTF8(sp);
|
||||
us.toLower(loc);
|
||||
out.clear();
|
||||
us.toUTF8String(out);
|
||||
}
|
||||
|
||||
auto to_lower_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void
|
||||
{
|
||||
auto cp = valid_u8_next_cp(s, i);
|
||||
auto us = icu::UnicodeString(UChar32(cp.cp));
|
||||
us.toLower(loc);
|
||||
auto u8_low = string();
|
||||
us.toUTF8String(u8_low);
|
||||
s.replace(i, cp.end_i - i, u8_low);
|
||||
}
|
||||
auto to_title_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void
|
||||
{
|
||||
auto cp = valid_u8_next_cp(s, i);
|
||||
auto us = icu::UnicodeString(UChar32(cp.cp));
|
||||
us.toTitle(nullptr, loc);
|
||||
auto u8_title = string();
|
||||
us.toUTF8String(u8_title);
|
||||
s.replace(i, cp.end_i - i, u8_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Determines casing (capitalization) type for a word.
|
||||
*
|
||||
* Casing is sometimes referred to as capitalization.
|
||||
*
|
||||
* @param s word.
|
||||
* @return The casing type.
|
||||
*/
|
||||
auto classify_casing(string_view s) -> Casing
|
||||
{
|
||||
size_t upper = 0;
|
||||
size_t lower = 0;
|
||||
for (size_t i = 0; i != size(s);) {
|
||||
char32_t c;
|
||||
valid_u8_advance_cp(s, i, c);
|
||||
if (u_isupper(c))
|
||||
upper++;
|
||||
else if (u_islower(c))
|
||||
lower++;
|
||||
// else neutral
|
||||
}
|
||||
if (upper == 0) // all lowercase, maybe with some neutral
|
||||
return Casing::SMALL; // most common case
|
||||
|
||||
auto first_cp = valid_u8_next_cp(s, 0);
|
||||
auto first_capital = u_isupper(first_cp.cp);
|
||||
if (first_capital && upper == 1)
|
||||
return Casing::INIT_CAPITAL; // second most common
|
||||
|
||||
if (lower == 0)
|
||||
return Casing::ALL_CAPITAL;
|
||||
|
||||
if (first_capital)
|
||||
return Casing::PASCAL;
|
||||
else
|
||||
return Casing::CAMEL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Check if word[i] or word[i-1] are uppercase
|
||||
*
|
||||
* Check if the two chars are alphabetic and at least one of them is in
|
||||
* uppercase.
|
||||
*
|
||||
* @return true if at least one is uppercase, false otherwise.
|
||||
*/
|
||||
auto has_uppercase_at_compound_word_boundary(string_view word, size_t i) -> bool
|
||||
{
|
||||
auto cp = valid_u8_next_cp(word, i);
|
||||
auto cp_prev = valid_u8_prev_cp(word, i);
|
||||
if (u_isupper(cp.cp)) {
|
||||
if (u_isalpha(cp_prev.cp))
|
||||
return true;
|
||||
}
|
||||
else if (u_isupper(cp_prev.cp) && u_isalpha(cp.cp))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Encoding_Converter::Encoding_Converter(const char* enc)
|
||||
{
|
||||
auto err = UErrorCode();
|
||||
cnv = ucnv_open(enc, &err);
|
||||
}
|
||||
|
||||
Encoding_Converter::~Encoding_Converter()
|
||||
{
|
||||
if (cnv)
|
||||
ucnv_close(cnv);
|
||||
}
|
||||
|
||||
Encoding_Converter::Encoding_Converter(const Encoding_Converter& other)
|
||||
{
|
||||
auto err = UErrorCode();
|
||||
cnv = ucnv_safeClone(other.cnv, nullptr, nullptr, &err);
|
||||
}
|
||||
|
||||
auto Encoding_Converter::operator=(const Encoding_Converter& other)
|
||||
-> Encoding_Converter&
|
||||
{
|
||||
this->~Encoding_Converter();
|
||||
auto err = UErrorCode();
|
||||
cnv = ucnv_safeClone(other.cnv, nullptr, nullptr, &err);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto Encoding_Converter::to_utf8(string_view in, string& out) -> bool
|
||||
{
|
||||
if (ucnv_getType(cnv) == UCNV_UTF8) {
|
||||
if (validate_utf8(in)) {
|
||||
out = in;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
out.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
auto err = U_ZERO_ERROR;
|
||||
auto len = ucnv_toAlgorithmic(UCNV_UTF8, cnv, out.data(), out.size(),
|
||||
in.data(), in.size(), &err);
|
||||
out.resize(len);
|
||||
if (err == U_BUFFER_OVERFLOW_ERROR) {
|
||||
err = U_ZERO_ERROR;
|
||||
ucnv_toAlgorithmic(UCNV_UTF8, cnv, out.data(), out.size(),
|
||||
in.data(), in.size(), &err);
|
||||
}
|
||||
return U_SUCCESS(err);
|
||||
}
|
||||
|
||||
auto replace_ascii_char(string& s, char from, char to) -> void
|
||||
{
|
||||
for (auto i = s.find(from); i != s.npos; i = s.find(from, i + 1)) {
|
||||
s[i] = to;
|
||||
}
|
||||
}
|
||||
|
||||
auto erase_chars(string& s, string_view erase_chars) -> void
|
||||
{
|
||||
if (erase_chars.empty())
|
||||
return;
|
||||
for (size_t i = 0, next_i = 0; i != size(s); i = next_i) {
|
||||
valid_u8_advance_index(s, next_i);
|
||||
auto enc_cp = string_view(&s[i], next_i - i);
|
||||
if (erase_chars.find(enc_cp) != erase_chars.npos) {
|
||||
s.erase(i, next_i - i);
|
||||
next_i = i;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Tests if word is a number.
|
||||
*
|
||||
* Allow numbers with dot ".", dash "-" or comma "," inbetween the digits, but
|
||||
* forbids double separators such as "..", "--" and ".,".
|
||||
*/
|
||||
auto is_number(string_view s) -> bool
|
||||
{
|
||||
if (s.empty())
|
||||
return false;
|
||||
|
||||
auto it = begin(s);
|
||||
if (s[0] == '-')
|
||||
++it;
|
||||
while (it != end(s)) {
|
||||
auto next = std::find_if(
|
||||
it, end(s), [](auto c) { return c < '0' || c > '9'; });
|
||||
if (next == it)
|
||||
return false;
|
||||
if (next == end(s))
|
||||
return true;
|
||||
it = next;
|
||||
auto c = *it;
|
||||
if (c == '.' || c == ',' || c == '-')
|
||||
++it;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto count_appereances_of(string_view haystack, string_view needles) -> size_t
|
||||
{
|
||||
auto ret = size_t(0);
|
||||
for (size_t i = 0, next_i = 0; i != size(haystack); i = next_i) {
|
||||
valid_u8_advance_index(haystack, next_i);
|
||||
auto enc_cp = string_view(&haystack[i], next_i - i);
|
||||
ret += needles.find(enc_cp) != needles.npos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
@@ -1,228 +0,0 @@
|
||||
/* Copyright 2016-2021 Dimitrij Mijoski
|
||||
*
|
||||
* This file is part of Nuspell.
|
||||
*
|
||||
* Nuspell is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Nuspell is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Nuspell. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NUSPELL_UTILS_HXX
|
||||
#define NUSPELL_UTILS_HXX
|
||||
|
||||
#include "nuspell_export.h"
|
||||
|
||||
#include <clocale>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#if !defined(_WIN32) && \
|
||||
(defined(__unix__) || defined(__unix) || \
|
||||
(defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__))
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <unicode/locid.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define likely(expr) __builtin_expect(!!(expr), 1)
|
||||
#define unlikely(expr) __builtin_expect(!!(expr), 0)
|
||||
#else
|
||||
#define likely(expr) (expr)
|
||||
#define unlikely(expr) (expr)
|
||||
#endif
|
||||
|
||||
struct UConverter; // unicode/ucnv.h
|
||||
|
||||
namespace nuspell {
|
||||
inline namespace v5 {
|
||||
|
||||
auto split(std::string_view s, char sep, std::vector<std::string>& out)
|
||||
-> std::vector<std::string>&;
|
||||
NUSPELL_EXPORT auto split_on_any_of(std::string_view s, const char* sep,
|
||||
std::vector<std::string>& out)
|
||||
-> std::vector<std::string>&;
|
||||
|
||||
NUSPELL_EXPORT auto utf32_to_utf8(std::u32string_view in, std::string& out)
|
||||
-> void;
|
||||
NUSPELL_EXPORT auto utf32_to_utf8(std::u32string_view in) -> std::string;
|
||||
|
||||
auto valid_utf8_to_32(std::string_view in, std::u32string& out) -> void;
|
||||
auto valid_utf8_to_32(std::string_view in) -> std::u32string;
|
||||
|
||||
auto utf8_to_16(std::string_view in) -> std::u16string;
|
||||
auto utf8_to_16(std::string_view in, std::u16string& out) -> bool;
|
||||
|
||||
auto validate_utf8(std::string_view s) -> bool;
|
||||
|
||||
NUSPELL_EXPORT auto is_all_ascii(std::string_view s) -> bool;
|
||||
|
||||
NUSPELL_EXPORT auto latin1_to_ucs2(std::string_view s) -> std::u16string;
|
||||
auto latin1_to_ucs2(std::string_view s, std::u16string& out) -> void;
|
||||
|
||||
NUSPELL_EXPORT auto is_all_bmp(std::u16string_view s) -> bool;
|
||||
|
||||
auto to_upper_ascii(std::string& s) -> void;
|
||||
|
||||
[[nodiscard]] NUSPELL_EXPORT auto to_upper(std::string_view in,
|
||||
const icu::Locale& loc)
|
||||
-> std::string;
|
||||
[[nodiscard]] NUSPELL_EXPORT auto to_title(std::string_view in,
|
||||
const icu::Locale& loc)
|
||||
-> std::string;
|
||||
[[nodiscard]] NUSPELL_EXPORT auto to_lower(std::string_view in,
|
||||
const icu::Locale& loc)
|
||||
-> std::string;
|
||||
|
||||
auto to_upper(std::string_view in, const icu::Locale& loc, std::string& out)
|
||||
-> void;
|
||||
auto to_title(std::string_view in, const icu::Locale& loc, std::string& out)
|
||||
-> void;
|
||||
auto to_lower(std::u32string_view in, const icu::Locale& loc,
|
||||
std::u32string& out) -> void;
|
||||
auto to_lower(std::string_view in, const icu::Locale& loc, std::string& out)
|
||||
-> void;
|
||||
auto to_lower_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void;
|
||||
auto to_title_char_at(std::string& s, size_t i, const icu::Locale& loc) -> void;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Enum that identifies the casing type of a word.
|
||||
*
|
||||
* Neutral characters like numbers are ignored, so "abc" and "abc123abc" are
|
||||
* both classified as small.
|
||||
*/
|
||||
enum class Casing : char {
|
||||
SMALL,
|
||||
INIT_CAPITAL,
|
||||
ALL_CAPITAL,
|
||||
CAMEL /**< @internal camelCase i.e. mixed case with first small */,
|
||||
PASCAL /**< @internal PascalCase i.e. mixed case with first capital */
|
||||
};
|
||||
|
||||
NUSPELL_EXPORT auto classify_casing(std::string_view s) -> Casing;
|
||||
|
||||
auto has_uppercase_at_compound_word_boundary(std::string_view word, size_t i)
|
||||
-> bool;
|
||||
|
||||
class Encoding_Converter {
|
||||
UConverter* cnv = nullptr;
|
||||
|
||||
public:
|
||||
Encoding_Converter() = default;
|
||||
explicit Encoding_Converter(const char* enc);
|
||||
explicit Encoding_Converter(const std::string& enc)
|
||||
: Encoding_Converter(enc.c_str())
|
||||
{
|
||||
}
|
||||
~Encoding_Converter();
|
||||
Encoding_Converter(const Encoding_Converter& other);
|
||||
Encoding_Converter(Encoding_Converter&& other) noexcept
|
||||
{
|
||||
cnv = other.cnv;
|
||||
cnv = nullptr;
|
||||
}
|
||||
auto operator=(const Encoding_Converter& other) -> Encoding_Converter&;
|
||||
auto operator=(Encoding_Converter&& other) noexcept
|
||||
-> Encoding_Converter&
|
||||
{
|
||||
std::swap(cnv, other.cnv);
|
||||
return *this;
|
||||
}
|
||||
auto to_utf8(std::string_view in, std::string& out) -> bool;
|
||||
auto valid() -> bool { return cnv != nullptr; }
|
||||
};
|
||||
|
||||
//#if _POSIX_VERSION >= 200809L
|
||||
#if defined(_POSIX_VERSION) && !defined(__NetBSD__) && !defined(__HAIKU__)
|
||||
class Setlocale_To_C_In_Scope {
|
||||
locale_t old_loc = nullptr;
|
||||
|
||||
public:
|
||||
Setlocale_To_C_In_Scope()
|
||||
: old_loc{uselocale(newlocale(0, "C", nullptr))}
|
||||
{
|
||||
}
|
||||
~Setlocale_To_C_In_Scope()
|
||||
{
|
||||
auto new_loc = uselocale(old_loc);
|
||||
if (new_loc != old_loc)
|
||||
freelocale(new_loc);
|
||||
}
|
||||
Setlocale_To_C_In_Scope(const Setlocale_To_C_In_Scope&) = delete;
|
||||
};
|
||||
#else
|
||||
class Setlocale_To_C_In_Scope {
|
||||
std::string old_name;
|
||||
#ifdef _WIN32
|
||||
int old_per_thread;
|
||||
#endif
|
||||
public:
|
||||
Setlocale_To_C_In_Scope() : old_name(setlocale(LC_ALL, nullptr))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
old_per_thread = _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
#endif
|
||||
auto x = setlocale(LC_ALL, "C");
|
||||
if (!x)
|
||||
old_name.clear();
|
||||
}
|
||||
~Setlocale_To_C_In_Scope()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_configthreadlocale(old_per_thread);
|
||||
if (old_per_thread == _ENABLE_PER_THREAD_LOCALE)
|
||||
#endif
|
||||
{
|
||||
if (!old_name.empty())
|
||||
setlocale(LC_ALL, old_name.c_str());
|
||||
}
|
||||
}
|
||||
Setlocale_To_C_In_Scope(const Setlocale_To_C_In_Scope&) = delete;
|
||||
};
|
||||
#endif
|
||||
|
||||
auto replace_ascii_char(std::string& s, char from, char to) -> void;
|
||||
auto erase_chars(std::string& s, std::string_view erase_chars) -> void;
|
||||
NUSPELL_EXPORT auto is_number(std::string_view s) -> bool;
|
||||
auto count_appereances_of(std::string_view haystack, std::string_view needles)
|
||||
-> size_t;
|
||||
|
||||
auto inline begins_with(std::string_view haystack, std::string_view needle)
|
||||
-> bool
|
||||
{
|
||||
return haystack.compare(0, needle.size(), needle) == 0;
|
||||
}
|
||||
|
||||
auto inline ends_with(std::string_view haystack, std::string_view needle)
|
||||
-> bool
|
||||
{
|
||||
return haystack.size() >= needle.size() &&
|
||||
haystack.compare(haystack.size() - needle.size(), needle.size(),
|
||||
needle) == 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto begin_ptr(T& x)
|
||||
{
|
||||
return x.data();
|
||||
}
|
||||
template <class T>
|
||||
auto end_ptr(T& x)
|
||||
{
|
||||
return x.data() + x.size();
|
||||
}
|
||||
} // namespace v5
|
||||
} // namespace nuspell
|
||||
#endif // NUSPELL_UTILS_HXX
|
||||
@@ -1,6 +1,7 @@
|
||||
add_library(
|
||||
# Name
|
||||
utils
|
||||
SHARED
|
||||
|
||||
# Headers
|
||||
jni_utils.h
|
||||
@@ -10,3 +11,5 @@ add_library(
|
||||
jni_utils.cpp
|
||||
log.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(utils PUBLIC log)
|
||||
|
||||
@@ -21,12 +21,12 @@ std::string utils::j2std_string(JNIEnv *env, jobject jStr) {
|
||||
auto cStr = reinterpret_cast<const char *>(env->GetDirectBufferAddress(jStr));
|
||||
auto size = env->GetDirectBufferCapacity(jStr);
|
||||
std::string stdStr(cStr, size);
|
||||
log_debug("spell j2s", stdStr);
|
||||
utils::log(ANDROID_LOG_DEBUG, "spell j2s", stdStr);
|
||||
return stdStr;
|
||||
}
|
||||
|
||||
jobject utils::std2j_string(JNIEnv *env, const std::string& stdStr) {
|
||||
log_debug("spell s2j", stdStr);
|
||||
utils::log(ANDROID_LOG_DEBUG, "spell s2j", stdStr);
|
||||
size_t byteCount = stdStr.length();
|
||||
auto cStr = stdStr.c_str();
|
||||
auto buffer = env->NewDirectByteBuffer((void *) cStr, byteCount);
|
||||
|
||||
@@ -15,67 +15,61 @@
|
||||
*/
|
||||
|
||||
#include <android/log.h>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
void utils::log_debug(const std::string &tag, const std::string &msg) {
|
||||
__android_log_print(ANDROID_LOG_DEBUG, tag.c_str(), "%s", msg.c_str());
|
||||
}
|
||||
|
||||
void utils::log_info(const std::string &tag, const std::string &msg) {
|
||||
__android_log_print(ANDROID_LOG_INFO, tag.c_str(), "%s", msg.c_str());
|
||||
}
|
||||
|
||||
void utils::log_warning(const std::string &tag, const std::string &msg) {
|
||||
__android_log_print(ANDROID_LOG_WARN, tag.c_str(), "%s", msg.c_str());
|
||||
}
|
||||
|
||||
void utils::log_error(const std::string &tag, const std::string &msg) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, tag.c_str(), "%s", msg.c_str());
|
||||
}
|
||||
|
||||
void utils::log_wtf(const std::string &tag, const std::string &msg) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, tag.c_str(), "%s", msg.c_str());
|
||||
void utils::log(int log_priority, const std::string &tag, const std::string &msg) {
|
||||
__android_log_print(log_priority, tag.c_str(), "%s", msg.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* Code below taken from here:
|
||||
* Code below based on:
|
||||
* https://codelab.wordpress.com/2014/11/03/how-to-use-standard-output-streams-for-logging-in-android-apps/
|
||||
*/
|
||||
static int pfd[2];
|
||||
static pthread_t thr;
|
||||
static const char *tag = "myapp";
|
||||
static bool already_started = false;
|
||||
int utils::start_stdout_stderr_logger(const std::string &app_name) {
|
||||
static bool already_started = false;
|
||||
if (already_started)
|
||||
return 0;
|
||||
|
||||
static void *thread_func(void*) {
|
||||
ssize_t rdsz;
|
||||
char buf[2048];
|
||||
while ((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
|
||||
if (buf[rdsz - 1] == '\n') --rdsz;
|
||||
buf[rdsz] = 0; /* add null-terminator */
|
||||
__android_log_write(ANDROID_LOG_DEBUG, tag, buf);
|
||||
int piperw[2];
|
||||
if (pipe(piperw) < 0) {
|
||||
std::string msg = "pipe(): ";
|
||||
msg += strerror(errno);
|
||||
utils::log(ANDROID_LOG_ERROR, "stdout/stderr logger", std::ref(msg));
|
||||
return 1;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int utils::start_stdout_stderr_logger(const char *app_name) {
|
||||
if (already_started) return 0;
|
||||
already_started = true;
|
||||
tag = app_name;
|
||||
|
||||
/* make stdout line-buffered and stderr unbuffered */
|
||||
setvbuf(stdout, nullptr, _IOLBF, 0);
|
||||
setvbuf(stderr, nullptr, _IONBF, 0);
|
||||
|
||||
/* create the pipe and redirect stdout and stderr */
|
||||
pipe(pfd);
|
||||
dup2(pfd[1], 1);
|
||||
dup2(pfd[1], 2);
|
||||
dup2(piperw[0], STDIN_FILENO);
|
||||
dup2(piperw[1], STDOUT_FILENO);
|
||||
dup2(piperw[1], STDERR_FILENO);
|
||||
close(piperw[0]);
|
||||
close(piperw[1]);
|
||||
|
||||
auto f = [](const std::string &tag) {
|
||||
std::string buf;
|
||||
while (std::getline(std::cin, buf)) {
|
||||
char &back = buf.back();
|
||||
if (back == '\n')
|
||||
back = '\0';
|
||||
utils::log(ANDROID_LOG_DEBUG, tag, std::ref(buf));
|
||||
}
|
||||
};
|
||||
|
||||
/* spawn the logging thread */
|
||||
if (pthread_create(&thr, nullptr, thread_func, nullptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
pthread_detach(thr);
|
||||
std::thread thr(f, app_name);
|
||||
thr.detach();
|
||||
|
||||
already_started = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,17 +17,14 @@
|
||||
#ifndef FLORISBOARD_LOG_H
|
||||
#define FLORISBOARD_LOG_H
|
||||
|
||||
#include <android/log.h>
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
void log_debug(const std::string& tag, const std::string& msg);
|
||||
void log_info(const std::string& tag, const std::string& msg);
|
||||
void log_warning(const std::string& tag, const std::string& msg);
|
||||
void log_error(const std::string& tag, const std::string& msg);
|
||||
void log_wtf(const std::string& tag, const std::string& msg);
|
||||
void log(int log_priority, const std::string &tag, const std::string &msg);
|
||||
|
||||
int start_stdout_stderr_logger(const char *app_name);
|
||||
int start_stdout_stderr_logger(const std::string &app_name);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
|
||||
Submodule app/src/main/icu4c deleted from c434a473c5
@@ -19,6 +19,7 @@ package dev.patrickgold.florisboard
|
||||
import android.app.Application
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Handler
|
||||
@@ -31,8 +32,6 @@ import dev.patrickgold.florisboard.ime.editor.EditorInstance
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyboardManager
|
||||
import dev.patrickgold.florisboard.ime.media.emoji.FlorisEmojiCompat
|
||||
import dev.patrickgold.florisboard.ime.nlp.NlpManager
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingManager
|
||||
import dev.patrickgold.florisboard.ime.spelling.SpellingService
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.GlideTypingManager
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeManager
|
||||
import dev.patrickgold.florisboard.lib.NativeStr
|
||||
@@ -45,14 +44,22 @@ import dev.patrickgold.florisboard.lib.devtools.flogInfo
|
||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||
import dev.patrickgold.florisboard.lib.io.AssetManager
|
||||
import dev.patrickgold.florisboard.lib.io.deleteContentsRecursively
|
||||
import dev.patrickgold.florisboard.lib.io.subFile
|
||||
import dev.patrickgold.florisboard.lib.toNativeStr
|
||||
import dev.patrickgold.jetpref.datastore.JetPref
|
||||
import java.io.File
|
||||
import org.florisboard.lib.kotlin.tryOrNull
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
* Global weak reference for the [FlorisApplication] class. This is needed as in certain scenarios an application
|
||||
* reference is needed, but the Android framework hasn't finished setting up
|
||||
*/
|
||||
private var FlorisApplicationReference = WeakReference<FlorisApplication?>(null)
|
||||
|
||||
@Suppress("unused")
|
||||
class FlorisApplication : Application() {
|
||||
companion object {
|
||||
private const val ICU_DATA_ASSET_PATH = "icu/icudt69l.dat"
|
||||
private const val ICU_DATA_ASSET_PATH = "icu4c/icudt73l.dat"
|
||||
|
||||
private external fun nativeInitICUData(path: NativeStr): Int
|
||||
|
||||
@@ -75,13 +82,12 @@ class FlorisApplication : Application() {
|
||||
val glideTypingManager = lazy { GlideTypingManager(this) }
|
||||
val keyboardManager = lazy { KeyboardManager(this) }
|
||||
val nlpManager = lazy { NlpManager(this) }
|
||||
val spellingManager = lazy { SpellingManager(this) }
|
||||
val spellingService = lazy { SpellingService(this) }
|
||||
val subtypeManager = lazy { SubtypeManager(this) }
|
||||
val themeManager = lazy { ThemeManager(this) }
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
FlorisApplicationReference = WeakReference(this)
|
||||
try {
|
||||
JetPref.configure(saveIntervalMs = 500)
|
||||
Flog.install(
|
||||
@@ -111,8 +117,8 @@ class FlorisApplication : Application() {
|
||||
fun init() {
|
||||
initICU(this)
|
||||
cacheDir?.deleteContentsRecursively()
|
||||
extensionManager.value.init()
|
||||
prefs.initializeBlocking(this)
|
||||
extensionManager.value.init()
|
||||
clipboardManager.value.initializeForContext(this)
|
||||
DictionaryManager.init(this)
|
||||
}
|
||||
@@ -120,7 +126,7 @@ class FlorisApplication : Application() {
|
||||
fun initICU(context: Context): Boolean {
|
||||
try {
|
||||
val androidAssetManager = context.assets ?: return false
|
||||
val icuTmpDataFile = File(context.cacheDir, "icudt.dat")
|
||||
val icuTmpDataFile = context.cacheDir.subFile("icudt.dat")
|
||||
icuTmpDataFile.outputStream().use { os ->
|
||||
androidAssetManager.open(ICU_DATA_ASSET_PATH).use { it.copyTo(os) }
|
||||
}
|
||||
@@ -154,35 +160,35 @@ class FlorisApplication : Application() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.florisApplication(): FlorisApplication {
|
||||
private tailrec fun Context.florisApplication(): FlorisApplication {
|
||||
return when (this) {
|
||||
is FlorisApplication -> this
|
||||
else -> this.applicationContext as FlorisApplication
|
||||
is ContextWrapper -> when {
|
||||
this.baseContext != null -> this.baseContext.florisApplication()
|
||||
else -> FlorisApplicationReference.get()!!
|
||||
}
|
||||
else -> tryOrNull { this.applicationContext as FlorisApplication } ?: FlorisApplicationReference.get()!!
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.appContext() = lazy { this.florisApplication() }
|
||||
fun Context.appContext() = lazyOf(this.florisApplication())
|
||||
|
||||
fun Context.assetManager() = lazy { this.florisApplication().assetManager.value }
|
||||
fun Context.assetManager() = this.florisApplication().assetManager
|
||||
|
||||
fun Context.cacheManager() = lazy { this.florisApplication().cacheManager.value }
|
||||
fun Context.cacheManager() = this.florisApplication().cacheManager
|
||||
|
||||
fun Context.clipboardManager() = lazy { this.florisApplication().clipboardManager.value }
|
||||
fun Context.clipboardManager() = this.florisApplication().clipboardManager
|
||||
|
||||
fun Context.editorInstance() = lazy { this.florisApplication().editorInstance.value }
|
||||
fun Context.editorInstance() = this.florisApplication().editorInstance
|
||||
|
||||
fun Context.extensionManager() = lazy { this.florisApplication().extensionManager.value }
|
||||
fun Context.extensionManager() = this.florisApplication().extensionManager
|
||||
|
||||
fun Context.glideTypingManager() = lazy { this.florisApplication().glideTypingManager.value }
|
||||
fun Context.glideTypingManager() = this.florisApplication().glideTypingManager
|
||||
|
||||
fun Context.keyboardManager() = lazy { this.florisApplication().keyboardManager.value }
|
||||
fun Context.keyboardManager() = this.florisApplication().keyboardManager
|
||||
|
||||
fun Context.nlpManager() = lazy { this.florisApplication().nlpManager.value }
|
||||
fun Context.nlpManager() = this.florisApplication().nlpManager
|
||||
|
||||
fun Context.spellingManager() = lazy { this.florisApplication().spellingManager.value }
|
||||
fun Context.subtypeManager() = this.florisApplication().subtypeManager
|
||||
|
||||
fun Context.spellingService() = lazy { this.florisApplication().spellingService.value }
|
||||
|
||||
fun Context.subtypeManager() = lazy { this.florisApplication().subtypeManager.value }
|
||||
|
||||
fun Context.themeManager() = lazy { this.florisApplication().themeManager.value }
|
||||
fun Context.themeManager() = this.florisApplication().themeManager
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
package dev.patrickgold.florisboard
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.BottomSheetValue
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.SwipeableDefaults
|
||||
import androidx.compose.material.rememberSwipeableState
|
||||
import androidx.compose.material.swipeable
|
||||
import androidx.compose.material3.BottomSheetDefaults
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.patrickgold.florisboard.ime.sheet.BottomSheetHostUi
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidClipboardManager
|
||||
import dev.patrickgold.florisboard.lib.android.stringRes
|
||||
import dev.patrickgold.florisboard.lib.android.systemService
|
||||
import dev.patrickgold.florisboard.lib.compose.ProvideLocalizedResources
|
||||
import dev.patrickgold.florisboard.lib.compose.stringRes
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.snyggBackground
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.snyggClip
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.solidColor
|
||||
import dev.patrickgold.florisboard.lib.snygg.ui.spSize
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class FlorisCopyToClipboardActivity : ComponentActivity() {
|
||||
private var error: CopyToClipboardError? = null
|
||||
private var bitmap: Bitmap? = null
|
||||
|
||||
internal enum class CopyToClipboardError {
|
||||
UNKNOWN_ERROR,
|
||||
ANDROID_VERSION_TO_OLD_ERROR,
|
||||
TYPE_NOT_SUPPORTED_ERROR;
|
||||
|
||||
@Composable
|
||||
fun showError(): String {
|
||||
val textId = when (this) {
|
||||
UNKNOWN_ERROR -> R.string.send_to_clipboard__unknown_error
|
||||
TYPE_NOT_SUPPORTED_ERROR -> R.string.send_to_clipboard__type_not_supported_error
|
||||
ANDROID_VERSION_TO_OLD_ERROR -> R.string.send_to_clipboard__android_version_to_old_error
|
||||
}
|
||||
return stringRes(id = textId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
finish()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val systemClipboardManager = this.systemService(AndroidClipboardManager::class)
|
||||
val type = intent.type
|
||||
val action = intent.action
|
||||
|
||||
if (Intent.ACTION_SEND != action || type == null) {
|
||||
error = CopyToClipboardError.UNKNOWN_ERROR
|
||||
} else {
|
||||
if (type.startsWith("image/")) {
|
||||
val hasExtraStream = intent.hasExtra(Intent.EXTRA_STREAM)
|
||||
if (!hasExtraStream) {
|
||||
error = CopyToClipboardError.TYPE_NOT_SUPPORTED_ERROR
|
||||
} else {
|
||||
// pasting images via virtual keyboard only available since Android 7.1 (API 25)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
|
||||
error = CopyToClipboardError.ANDROID_VERSION_TO_OLD_ERROR
|
||||
} else {
|
||||
val uri: Uri? =
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM)
|
||||
} else {
|
||||
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
|
||||
}
|
||||
val clip = ClipData.newUri(contentResolver, "image", uri)
|
||||
systemClipboardManager.setPrimaryClip(clip)
|
||||
bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, uri)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error = CopyToClipboardError.TYPE_NOT_SUPPORTED_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
setContent {
|
||||
ProvideLocalizedResources(this, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
FlorisImeTheme {
|
||||
BottomSheetHostUi(isShowing = true, onHide = { finish() }) {
|
||||
val panelStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditor)
|
||||
val headerStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorHeader)
|
||||
val subheaderStyle = FlorisImeTheme.style.get(FlorisImeUi.SmartbarActionsEditorSubheader)
|
||||
val context = LocalContext.current
|
||||
Swipable {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.snyggBackground(
|
||||
context,
|
||||
panelStyle,
|
||||
fallbackColor = FlorisImeTheme.fallbackSurfaceColor()
|
||||
)
|
||||
.snyggClip(panelStyle)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.snyggBackground(context, headerStyle),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Spacer(modifier = Modifier.weight(1F))
|
||||
BottomSheetDefaults.DragHandle(
|
||||
color = headerStyle.foreground.solidColor(
|
||||
context,
|
||||
default = FlorisImeTheme.fallbackContentColor()
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1F))
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.snyggBackground(context, headerStyle),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
text = error?.showError()
|
||||
?: bitmap?.let { stringRes(id = R.string.send_to_clipboard__description__copied_image_to_clipboard) }
|
||||
?: stringRes(R.string.send_to_clipboard__unknown_error),
|
||||
color = headerStyle.foreground.solidColor(
|
||||
context,
|
||||
default = FlorisImeTheme.fallbackContentColor()
|
||||
),
|
||||
fontSize = headerStyle.fontSize.spSize(),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Spacer(Modifier.height(48.dp))
|
||||
}
|
||||
bitmap?.let {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
bitmap = bitmap!!.asImageBitmap(),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
Button(
|
||||
onClick = { finish() },
|
||||
modifier = Modifier.align(alignment = Alignment.End),
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
//containerColor = buttonContainer.background.solidColor(context = context),
|
||||
contentColor = subheaderStyle.foreground.solidColor(context = context),
|
||||
)
|
||||
) {
|
||||
Text(text = stringRes(id = R.string.action__ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
internal fun Swipable(
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val swipeableState = rememberSwipeableState(
|
||||
initialValue = BottomSheetValue.Expanded,
|
||||
confirmStateChange = {
|
||||
if (it == BottomSheetValue.Collapsed) {
|
||||
finish()
|
||||
}
|
||||
true
|
||||
}
|
||||
)
|
||||
BoxWithConstraints {
|
||||
val constraintsScope = this
|
||||
val maxHeight = with(LocalDensity.current) {
|
||||
constraintsScope.maxHeight.toPx()
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.swipeable(
|
||||
state = swipeableState,
|
||||
orientation = Orientation.Vertical,
|
||||
anchors = mapOf(
|
||||
0f to BottomSheetValue.Expanded,
|
||||
maxHeight to BottomSheetValue.Collapsed,
|
||||
),
|
||||
resistance = SwipeableDefaults.resistanceConfig(
|
||||
anchors = setOf(0f, maxHeight),
|
||||
factorAtMin = 0F
|
||||
)
|
||||
)
|
||||
.offset {
|
||||
IntOffset(
|
||||
x = 0,
|
||||
y = swipeableState.offset.value.roundToInt()
|
||||
)
|
||||
}
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.os.Bundle
|
||||
import android.util.Size
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
@@ -63,6 +64,7 @@ import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.AbstractComposeView
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
@@ -70,6 +72,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import dev.patrickgold.florisboard.app.FlorisAppActivity
|
||||
import dev.patrickgold.florisboard.app.devtools.DevtoolsOverlay
|
||||
import dev.patrickgold.florisboard.app.florisPreferenceModel
|
||||
@@ -86,8 +89,12 @@ import dev.patrickgold.florisboard.ime.lifecycle.LifecycleInputMethodService
|
||||
import dev.patrickgold.florisboard.ime.media.MediaInputLayout
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
|
||||
import dev.patrickgold.florisboard.ime.onehanded.OneHandedPanel
|
||||
import dev.patrickgold.florisboard.ime.sheet.BottomSheetHostUi
|
||||
import dev.patrickgold.florisboard.ime.sheet.isBottomSheetShowing
|
||||
import dev.patrickgold.florisboard.ime.smartbar.ExtendedActionsPlacement
|
||||
import dev.patrickgold.florisboard.ime.smartbar.SmartbarLayout
|
||||
import dev.patrickgold.florisboard.ime.smartbar.quickaction.QuickActionsEditorPanel
|
||||
import dev.patrickgold.florisboard.ime.text.TextInputLayout
|
||||
import dev.patrickgold.florisboard.ime.text.smartbar.SecondaryRowPlacement
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeTheme
|
||||
import dev.patrickgold.florisboard.ime.theme.FlorisImeUi
|
||||
import dev.patrickgold.florisboard.lib.android.AndroidInternalR
|
||||
@@ -116,6 +123,7 @@ import dev.patrickgold.florisboard.lib.snygg.ui.spSize
|
||||
import dev.patrickgold.florisboard.lib.util.ViewUtils
|
||||
import dev.patrickgold.florisboard.lib.util.debugSummarize
|
||||
import dev.patrickgold.jetpref.datastore.model.observeAsState
|
||||
import org.florisboard.lib.kotlin.collectLatestIn
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
@@ -265,7 +273,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
FlorisImeServiceReference = WeakReference(this)
|
||||
subtypeManager.activeSubtype.observe(this) { subtype ->
|
||||
subtypeManager.activeSubtypeFlow.collectLatestIn(lifecycleScope) { subtype ->
|
||||
val config = Configuration(resources.configuration)
|
||||
config.setLocale(subtype.primaryLocale)
|
||||
resourcesContext = createConfigurationContext(config)
|
||||
@@ -274,6 +282,10 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
|
||||
override fun onCreateInputView(): View {
|
||||
super.installViewTreeOwners()
|
||||
// Instantiate and install bottom sheet host UI view
|
||||
val bottomSheetView = FlorisBottomSheetHostUiView()
|
||||
window.window!!.findViewById<ViewGroup>(android.R.id.content).addView(bottomSheetView)
|
||||
// Instantiate and return input view
|
||||
val composeView = ComposeInputView()
|
||||
inputWindowView = composeView
|
||||
return composeView
|
||||
@@ -324,7 +336,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
activeState.batchEdit {
|
||||
activeState.imeUiMode = ImeUiMode.TEXT
|
||||
activeState.isSelectionMode = editorInfo.initialSelection.isSelectionMode
|
||||
editorInstance.handleStartInputView(editorInfo)
|
||||
editorInstance.handleStartInputView(editorInfo, isRestart = restarting)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,6 +395,10 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
flogInfo(LogTopic.IMS_EVENTS)
|
||||
}
|
||||
isWindowShown = false
|
||||
activeState.batchEdit {
|
||||
activeState.isActionsOverflowVisible = false
|
||||
activeState.isActionsEditorVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEvaluateFullscreenMode(): Boolean {
|
||||
@@ -401,7 +417,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
|
||||
override fun onUpdateExtractingVisibility(info: EditorInfo?) {
|
||||
if (info != null) {
|
||||
editorInstance.handleStartInputView(FlorisEditorInfo.wrap(info))
|
||||
editorInstance.handleStartInputView(FlorisEditorInfo.wrap(info), isRestart = true)
|
||||
}
|
||||
when (prefs.keyboard.landscapeInputUiMode.get()) {
|
||||
LandscapeInputUiMode.DYNAMICALLY_SHOW -> super.onUpdateExtractingVisibility(info)
|
||||
@@ -462,16 +478,18 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
val visibleTopY = inputWindowView.height - inputViewSize.height
|
||||
val needAdditionalOverlay =
|
||||
prefs.smartbar.enabled.get() &&
|
||||
prefs.smartbar.secondaryActionsEnabled.get() &&
|
||||
prefs.smartbar.secondaryActionsExpanded.get() &&
|
||||
prefs.smartbar.secondaryActionsPlacement.get() == SecondaryRowPlacement.OVERLAY_APP_UI &&
|
||||
prefs.smartbar.layout.get() == SmartbarLayout.SUGGESTIONS_ACTIONS_EXTENDED &&
|
||||
prefs.smartbar.extendedActionsExpanded.get() &&
|
||||
prefs.smartbar.extendedActionsPlacement.get() == ExtendedActionsPlacement.OVERLAY_APP_UI &&
|
||||
keyboardManager.activeState.imeUiMode == ImeUiMode.TEXT
|
||||
|
||||
outInsets.contentTopInsets = visibleTopY
|
||||
outInsets.visibleTopInsets = visibleTopY
|
||||
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_REGION
|
||||
val left = 0
|
||||
val top = visibleTopY - if (needAdditionalOverlay) FlorisImeSizing.Static.smartbarHeightPx else 0
|
||||
val top = if (keyboardManager.activeState.isBottomSheetShowing()) { 0 } else {
|
||||
visibleTopY - if (needAdditionalOverlay) FlorisImeSizing.Static.smartbarHeightPx else 0
|
||||
}
|
||||
val right = inputViewSize.width
|
||||
val bottom = inputWindowView.height
|
||||
outInsets.touchableRegion.set(left, top, right, bottom)
|
||||
@@ -541,14 +559,16 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
private fun ImeUi() {
|
||||
val activeState by keyboardManager.observeActiveState()
|
||||
val state by keyboardManager.activeState.collectAsState()
|
||||
val keyboardStyle = FlorisImeTheme.style.get(
|
||||
element = FlorisImeUi.Keyboard,
|
||||
mode = activeState.inputShiftState.value,
|
||||
mode = state.inputShiftState.value,
|
||||
)
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
SideEffect {
|
||||
keyboardManager.activeState.layoutDirection = layoutDirection
|
||||
if (keyboardManager.activeState.layoutDirection != layoutDirection) {
|
||||
keyboardManager.activeState.layoutDirection = layoutDirection
|
||||
}
|
||||
}
|
||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||
SnyggSurface(
|
||||
@@ -592,7 +612,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
.weight(keyboardWeight)
|
||||
.wrapContentHeight(),
|
||||
) {
|
||||
when (activeState.imeUiMode) {
|
||||
when (state.imeUiMode) {
|
||||
ImeUiMode.TEXT -> TextInputLayout()
|
||||
ImeUiMode.MEDIA -> MediaInputLayout()
|
||||
ImeUiMode.CLIPBOARD -> ClipboardInputLayout()
|
||||
@@ -618,6 +638,11 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =
|
||||
if (keyboardManager.onHardwareKeyDown(keyCode, event)) true
|
||||
else super.onKeyDown(keyCode, event)
|
||||
|
||||
|
||||
private inner class ComposeInputView : AbstractComposeView(this) {
|
||||
init {
|
||||
isHapticFeedbackEnabled = true
|
||||
@@ -639,6 +664,37 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
}
|
||||
}
|
||||
|
||||
private inner class FlorisBottomSheetHostUiView : AbstractComposeView(this) {
|
||||
init {
|
||||
isHapticFeedbackEnabled = true
|
||||
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val keyboardManager by context.keyboardManager()
|
||||
val state by keyboardManager.activeState.collectAsState()
|
||||
|
||||
ProvideLocalizedResources(resourcesContext, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
FlorisImeTheme {
|
||||
BottomSheetHostUi(
|
||||
isShowing = state.isBottomSheetShowing(),
|
||||
onHide = {
|
||||
keyboardManager.activeState.isActionsEditorVisible = false
|
||||
},
|
||||
) {
|
||||
QuickActionsEditorPanel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAccessibilityClassName(): CharSequence {
|
||||
return javaClass.name
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ComposeExtractedLandscapeInputView(eet: ExtractEditText?) : FrameLayout(this) {
|
||||
val composeView: ComposeView
|
||||
val extractEditText: ExtractEditText
|
||||
@@ -662,6 +718,7 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
|
||||
@Composable
|
||||
fun Content() {
|
||||
val context = LocalContext.current
|
||||
ProvideLocalizedResources(resourcesContext, forceLayoutDirection = LayoutDirection.Ltr) {
|
||||
FlorisImeTheme {
|
||||
val layoutStyle = FlorisImeTheme.style.get(FlorisImeUi.ExtractedLandscapeInputLayout)
|
||||
@@ -670,21 +727,21 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
val activeEditorInfo by editorInstance.activeInfoFlow.collectAsState()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.snyggBackground(layoutStyle, FlorisImeTheme.fallbackSurfaceColor()),
|
||||
.snyggBackground(context, layoutStyle, FlorisImeTheme.fallbackSurfaceColor()),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val fieldColor = fieldStyle.foreground.solidColor(FlorisImeTheme.fallbackContentColor())
|
||||
val fieldColor = fieldStyle.foreground.solidColor(context, FlorisImeTheme.fallbackContentColor())
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxHeight()
|
||||
.weight(1f)
|
||||
.snyggShadow(fieldStyle)
|
||||
.snyggBorder(fieldStyle)
|
||||
.snyggBackground(fieldStyle),
|
||||
.snyggBorder(context, fieldStyle)
|
||||
.snyggBackground(context, fieldStyle),
|
||||
factory = { extractEditText },
|
||||
update = { view ->
|
||||
view.background = null
|
||||
@@ -712,8 +769,8 @@ class FlorisImeService : LifecycleInputMethodService() {
|
||||
?: "ACTION",
|
||||
shape = actionStyle.shape.shape(),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = actionStyle.background.solidColor(FlorisImeTheme.fallbackContentColor()),
|
||||
contentColor = actionStyle.foreground.solidColor(FlorisImeTheme.fallbackSurfaceColor()),
|
||||
backgroundColor = actionStyle.background.solidColor(context, FlorisImeTheme.fallbackContentColor()),
|
||||
contentColor = actionStyle.foreground.solidColor(context, FlorisImeTheme.fallbackSurfaceColor()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user