mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-11 19:35:32 +00:00
Merge branch 'feat/developer/kmc-convert' into feat/developer/kmc-convert-validateKeylayout
# Conflicts: # developer/src/common/web/utils/src/xml-utils.ts # developer/src/kmc-convert/src/converter-messages.ts # developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-file-reader.ts # developer/src/kmc-convert/src/keylayout-to-kmn/keylayout-to-kmn-converter.ts # developer/src/kmc-convert/src/keylayout-to-kmn/kmn-file-writer.ts
This commit is contained in:
commit
cebbda981f
789 changed files with 13522 additions and 9415 deletions
|
|
@ -5,9 +5,7 @@ module.exports = {
|
|||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
// TODO: we need to move to the following, but this gets us started with infrastructure without breaking our build
|
||||
// extends: [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended"],
|
||||
extends: ["plugin:@typescript-eslint/eslint-recommended"],
|
||||
extends: [ "plugin:@typescript-eslint/eslint-recommended"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
|
|
|
|||
9
.gitattributes
vendored
Normal file
9
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Always use LF for Dockerfile - otherwise HEREDOCs in Dockerfile
|
||||
# will not work on Windows - we end up with a filename `foo\r` for
|
||||
# the command
|
||||
# ```Dockerfile
|
||||
# RUN <<EOF cat > foo
|
||||
# echo "Hello world"
|
||||
# EOF
|
||||
# ```
|
||||
Dockerfile text eol=lf
|
||||
|
|
@ -25,13 +25,13 @@ runs:
|
|||
using: 'composite'
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: keyman-srcpkg
|
||||
path: artifacts/keyman-srcpkg
|
||||
|
||||
- name: Build
|
||||
uses: sillsdev/gha-ubuntu-packaging@7b56f50d5d5537e9e9cafd3f6139ec6da69cfcda # v1.1
|
||||
uses: sillsdev/gha-ubuntu-packaging@556b268762be9bea0f39861a7392587211ef6a58 # v2.0.1
|
||||
with:
|
||||
dist: "${{ inputs.dist }}"
|
||||
platform: "${{ inputs.arch }}"
|
||||
|
|
@ -49,7 +49,7 @@ runs:
|
|||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store binary packages
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: keyman-binarypkgs-${{ inputs.dist }}_${{ inputs.arch }}
|
||||
path: |
|
||||
|
|
|
|||
54
.github/labeler.yml
vendored
54
.github/labeler.yml
vendored
|
|
@ -11,51 +11,56 @@ docs: docs/**
|
|||
# Add labels based on changed files using actions/labeler
|
||||
#
|
||||
|
||||
android/: android/**
|
||||
android/:
|
||||
- android/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/android/**
|
||||
android/app/: android/KMAPro/**
|
||||
android/engine/: android/KMEA/**
|
||||
android/samples/: android/Samples/**
|
||||
|
||||
common/:
|
||||
- common/**
|
||||
- resources/**
|
||||
|
||||
common/models/templates/: web/src/engine/predictive-text/templates/**
|
||||
common/models/wordbreakers/: web/src/engine/predictive-text/wordbreakers/**
|
||||
|
||||
common/resources/: resources/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/common/**
|
||||
common/web/: common/web/**
|
||||
|
||||
core/:
|
||||
- core/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/core/**
|
||||
|
||||
developer/:
|
||||
- developer/**
|
||||
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/developer/**
|
||||
developer/compilers/:
|
||||
- developer/src/kmc/**
|
||||
- developer/src/kmcmplib/**
|
||||
- developer/src/kmc-*/**
|
||||
|
||||
developer/ide/:
|
||||
- developer/src/server/**
|
||||
- developer/src/tike/**
|
||||
|
||||
|
||||
ios/: ios/**
|
||||
ios/:
|
||||
- ios/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/ios/**
|
||||
ios/app/: ios/keyman/**
|
||||
ios/engine/: ios/engine/**
|
||||
ios/samples/: ios/samples/**
|
||||
|
||||
linux/: linux/**
|
||||
linux/:
|
||||
- linux/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/linux/**
|
||||
linux/config/: linux/keyman-config/**
|
||||
linux/engine/:
|
||||
- linux/ibus-keyman/**
|
||||
- linux/legacy/ibus-kmfl/**
|
||||
- linux/legacy/kmflcomp/**
|
||||
- linux/legacy/libkmfl/**
|
||||
linux/engine/: linux/ibus-keyman/**
|
||||
|
||||
mac/: mac/**
|
||||
mac/:
|
||||
- mac/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/mac/**
|
||||
# mac/config/:
|
||||
# mac/engine/: mac/**
|
||||
|
||||
|
|
@ -65,12 +70,21 @@ oem/fv/android/: oem/firstvoices/android/**
|
|||
oem/fv/ios/: oem/firstvoices/ios/**
|
||||
oem/fv/windows/: oem/firstvoices/windows/**
|
||||
|
||||
web/: web/**
|
||||
resources/: resources/**
|
||||
|
||||
web/:
|
||||
- web/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/web/**
|
||||
# web/bookmarklet/
|
||||
web/engine/: web/source/**
|
||||
web/ui/: web/source/kmwui*
|
||||
web/samples/: web/samples/**
|
||||
web/predictive-text/: web/src/engine/predictive-text/**
|
||||
|
||||
windows/: windows/**
|
||||
windows/:
|
||||
- windows/**
|
||||
- resources/teamcity/includes/**
|
||||
- resources/teamcity/windows/**
|
||||
windows/config/: windows/src/desktop/**
|
||||
windows/engine/: windows/src/engine/**
|
||||
|
|
|
|||
11
.github/multi-labeler.yml
vendored
11
.github/multi-labeler.yml
vendored
|
|
@ -33,6 +33,9 @@ labels:
|
|||
- label: 'fix'
|
||||
matcher:
|
||||
title: '^fix(\(|:)'
|
||||
- label: 'maint'
|
||||
matcher:
|
||||
title: '^maint(\(|:)'
|
||||
- label: 'refactor'
|
||||
matcher:
|
||||
title: '^refactor(\(|:)'
|
||||
|
|
@ -57,11 +60,6 @@ labels:
|
|||
matcher:
|
||||
title: '(🍒|:cherries:)'
|
||||
|
||||
# long-lived feature branches
|
||||
- label: 'feature-branch'
|
||||
matcher:
|
||||
branch: '^feature-.+'
|
||||
|
||||
#
|
||||
# Scopes that we look for in the PR title
|
||||
#
|
||||
|
|
@ -90,6 +88,9 @@ labels:
|
|||
- label: 'oem/'
|
||||
matcher:
|
||||
title: '\(.*oem.*\):'
|
||||
- label: 'resources/'
|
||||
matcher:
|
||||
title: '\(.*resources.*\):'
|
||||
- label: 'web/'
|
||||
matcher:
|
||||
title: '\(.*web.*\):'
|
||||
|
|
|
|||
10
.github/workflows/api-verification.yml
vendored
10
.github/workflows/api-verification.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
name: Verify API for libkeymancore*.so
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
VERSION: ${{ steps.environment_step.outputs.VERSION }}
|
||||
KEYMAN_VERSION: ${{ steps.environment_step.outputs.KEYMAN_VERSION }}
|
||||
PRERELEASE_TAG: ${{ steps.environment_step.outputs.PRERELEASE_TAG }}
|
||||
GIT_SHA: ${{ steps.environment_step.outputs.GIT_SHA }}
|
||||
GIT_BASE: ${{ steps.environment_step.outputs.GIT_BASE }}
|
||||
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Restore artifacts
|
||||
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
|
||||
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
with:
|
||||
path: |
|
||||
artifacts
|
||||
|
|
@ -53,7 +53,7 @@ jobs:
|
|||
-f context="$STATUS_CONTEXT"
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
|
||||
with:
|
||||
ref: '${{ steps.environment_step.outputs.GIT_SHA }}'
|
||||
fetch-depth: 0
|
||||
|
|
@ -69,7 +69,7 @@ jobs:
|
|||
run: |
|
||||
echo "Verify API for libkeymancore*.so (${{ steps.environment_step.outputs.GIT_BRANCH }}, branch ${{ steps.environment_step.outputs.GIT_BASE_BRANCH }}, by ${{ steps.environment_step.outputs.GIT_USER }}):" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
BIN_PACKAGE=$(ls "${GITHUB_WORKSPACE}/artifacts/" | grep "${PKG_NAME}[0-9]*_${{ steps.environment_step.outputs.VERSION }}-1${{ steps.environment_step.outputs.PRERELEASE_TAG }}+$(lsb_release -c -s)1_amd64.deb")
|
||||
BIN_PACKAGE=$(ls "${GITHUB_WORKSPACE}/artifacts/" | grep "${PKG_NAME}[0-9]*_${{ steps.environment_step.outputs.KEYMAN_VERSION }}-1${{ steps.environment_step.outputs.PRERELEASE_TAG }}+$(lsb_release -c -s)1_amd64.deb")
|
||||
cd ${{ github.workspace }}/keyman/linux
|
||||
./scripts/deb-packaging.sh \
|
||||
--gha \
|
||||
|
|
@ -79,7 +79,7 @@ jobs:
|
|||
verify 2>> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Archive .symbols file
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: libkeymancore.symbols
|
||||
path: ${{ github.workspace }}/keyman/linux/debian/tmp/DEBIAN/symbols
|
||||
|
|
|
|||
4
.github/workflows/crowdin.yml
vendored
4
.github/workflows/crowdin.yml
vendored
|
|
@ -13,10 +13,10 @@ jobs:
|
|||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: crowdin action
|
||||
uses: crowdin/github-action@1.3.2
|
||||
uses: crowdin/github-action@2.7.0
|
||||
with:
|
||||
upload_sources: true
|
||||
|
||||
|
|
|
|||
45
.github/workflows/deb-packaging.yml
vendored
45
.github/workflows/deb-packaging.yml
vendored
|
|
@ -37,11 +37,11 @@ jobs:
|
|||
if: github.repository == 'keymanapp/keyman'
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
VERSION: ${{ steps.version_step.outputs.VERSION }}
|
||||
KEYMAN_VERSION: ${{ steps.version_step.outputs.KEYMAN_VERSION }}
|
||||
PRERELEASE_TAG: ${{ steps.prerelease_tag.outputs.PRERELEASE_TAG }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
|
||||
with:
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
|
||||
|
|
@ -72,10 +72,10 @@ jobs:
|
|||
- name: Build source package
|
||||
id: build_source_package
|
||||
run: |
|
||||
export TIER=$(cat TIER.md)
|
||||
export KEYMAN_TIER=$(cat TIER.md)
|
||||
export GHA_TEST_BUILD="${{ github.event.client_payload.isTestBuild }}"
|
||||
export GHA_BRANCH="${{ github.event.client_payload.branch }}"
|
||||
echo "TIER=$TIER" >> $GITHUB_ENV
|
||||
echo "KEYMAN_TIER=$KEYMAN_TIER" >> $GITHUB_ENV
|
||||
echo "GHA_TEST_BUILD=${GHA_TEST_BUILD}" >> $GITHUB_ENV
|
||||
echo "GHA_BRANCH=${GHA_BRANCH}" >> $GITHUB_ENV
|
||||
cd linux
|
||||
|
|
@ -87,7 +87,7 @@ jobs:
|
|||
run: |
|
||||
THIS_SCRIPT="$GITHUB_WORKSPACE/.github/workflows/deb-packaging.yml"
|
||||
. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh"
|
||||
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "KEYMAN_VERSION=${KEYMAN_VERSION:-${VERSION}}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set prerelease tag as output parameter
|
||||
id: prerelease_tag
|
||||
|
|
@ -103,16 +103,16 @@ jobs:
|
|||
- name: Output which branch or PR we're building plus name of .dsc file
|
||||
run: |
|
||||
if [ "${{ github.event.client_payload.isTestBuild }}" == "true" ]; then
|
||||
echo ":checkered_flag: **Test build of version ${{ steps.version_step.outputs.VERSION }} for ${{ github.event.client_payload.branch }}**" >> $GITHUB_STEP_SUMMARY
|
||||
echo ":checkered_flag: **Test build of version ${{ steps.version_step.outputs.KEYMAN_VERSION }} for ${{ github.event.client_payload.branch }}**" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo ":ship: **Release build of ${{ github.event.client_payload.branch }} branch (${{ github.event.client_payload.branch}}), version ${{ steps.version_step.outputs.VERSION }}**" >> $GITHUB_STEP_SUMMARY
|
||||
echo ":ship: **Release build of ${{ github.event.client_payload.branch }} branch (${{ github.event.client_payload.branch}}), version ${{ steps.version_step.outputs.KEYMAN_VERSION }}**" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo ":gift: Generated source package:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- $(find . -name keyman_\*.dsc)" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store source package
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: keyman-srcpkg
|
||||
path: |
|
||||
|
|
@ -131,7 +131,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
|
||||
with:
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
sparse-checkout: '.github/actions/'
|
||||
|
|
@ -140,7 +140,7 @@ jobs:
|
|||
uses: ./.github/actions/build-binary-packages
|
||||
with:
|
||||
dist: ${{ matrix.dist }}
|
||||
version: ${{ needs.sourcepackage.outputs.VERSION }}
|
||||
version: ${{ needs.sourcepackage.outputs.KEYMAN_VERSION }}
|
||||
prerelease_tag: ${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}
|
||||
deb_fullname: ${{env.DEBFULLNAME}}
|
||||
deb_email: ${{env.DEBEMAIL}}
|
||||
|
|
@ -157,7 +157,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
|
||||
with:
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
sparse-checkout: '.github/actions/'
|
||||
|
|
@ -166,7 +166,7 @@ jobs:
|
|||
uses: ./.github/actions/build-binary-packages
|
||||
with:
|
||||
dist: ${{ matrix.dist }}
|
||||
version: ${{ needs.sourcepackage.outputs.VERSION }}
|
||||
version: ${{ needs.sourcepackage.outputs.KEYMAN_VERSION }}
|
||||
prerelease_tag: ${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}
|
||||
deb_fullname: ${{env.DEBFULLNAME}}
|
||||
deb_email: ${{env.DEBEMAIL}}
|
||||
|
|
@ -178,7 +178,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
# - name: Download Artifacts
|
||||
# uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
# uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
# with:
|
||||
# path: artifacts
|
||||
# merge-multiple: true
|
||||
|
|
@ -198,7 +198,7 @@ jobs:
|
|||
# autopkgtest -B *.deb keyman_*.dsc -- qemu autopkgtest-jammy-amd64.img
|
||||
- name: Ignore
|
||||
run: |
|
||||
echo "Ignored for now - until working solution is in place"
|
||||
echo "Ignored for now - until working solution is in place (#13777)"
|
||||
|
||||
deb_signing:
|
||||
name: Sign source and binary packages
|
||||
|
|
@ -211,8 +211,8 @@ jobs:
|
|||
- name: Sign packages
|
||||
uses: sillsdev/gha-deb-signing@a38dbde6bc9afabede5e07609105acc83c760ad4 # v0.6
|
||||
with:
|
||||
src-pkg-name: "keyman_${{ needs.sourcepackage.outputs.VERSION }}-1_source.changes"
|
||||
bin-pkg-name: "keyman_${{ needs.sourcepackage.outputs.VERSION }}-1${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}+"
|
||||
src-pkg-name: "keyman_${{ needs.sourcepackage.outputs.KEYMAN_VERSION }}-1_source.changes"
|
||||
bin-pkg-name: "keyman_${{ needs.sourcepackage.outputs.KEYMAN_VERSION }}-1${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}+"
|
||||
artifacts-prefix: "keyman-"
|
||||
artifacts-result-name: "keyman-signedpkgs"
|
||||
gpg-signing-key: "${{ secrets.GPG_SIGNING_KEY }}"
|
||||
|
|
@ -247,7 +247,7 @@ jobs:
|
|||
echo "::endgroup::"
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: keyman-signedpkgs
|
||||
|
||||
|
|
@ -293,7 +293,7 @@ jobs:
|
|||
echo "::endgroup::"
|
||||
|
||||
echo -e "::group::${COLOR_GREEN}Uploading binary packages"
|
||||
pattern="keyman_${{ needs.sourcepackage.outputs.VERSION }}.+\+(.*)[0-9]_[^.]+.changes"
|
||||
pattern="keyman_${{ needs.sourcepackage.outputs.KEYMAN_VERSION }}.+\+(.*)[0-9]_[^.]+.changes"
|
||||
for f in *_amd64.changes; do
|
||||
if [[ $f =~ $pattern ]]; then
|
||||
dist=${BASH_REMATCH[1]}
|
||||
|
|
@ -303,20 +303,21 @@ jobs:
|
|||
echo "::endgroup::"
|
||||
|
||||
prepare_api_verification:
|
||||
name: Verify API for libkeymancore.so
|
||||
name: Prepare API verification
|
||||
needs: [sourcepackage, binary_packages_released]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
path: artifacts
|
||||
pattern: keyman-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Save environment
|
||||
run: |
|
||||
echo "VERSION=${{ needs.sourcepackage.outputs.VERSION }}" > artifacts/env
|
||||
echo "KEYMAN_VERSION=${{ needs.sourcepackage.outputs.KEYMAN_VERSION }}" > artifacts/env
|
||||
echo "PRERELEASE_TAG=${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}" >> artifacts/env
|
||||
echo "GIT_SHA=${{ github.event.client_payload.buildSha }}" >> artifacts/env
|
||||
echo "GIT_BASE=${{ github.event.client_payload.baseRef }}" >> artifacts/env
|
||||
|
|
@ -326,7 +327,7 @@ jobs:
|
|||
echo "GIT_USER=${{ github.event.client_payload.user }}" >> artifacts/env
|
||||
|
||||
- name: Cache artifacts
|
||||
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
|
||||
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
with:
|
||||
path: |
|
||||
artifacts
|
||||
|
|
|
|||
|
|
@ -384,10 +384,11 @@ group.
|
|||
| `auto` | [search][search-auto] | For PRs only: automatically-opened PRs, e.g. opened by CI. |
|
||||
| `bug` | [search][search-bug] | For issues only: confirmed bugs or reports that are very likely to be bugs. PRs use `fix` to mark a bug fix. |
|
||||
| `change` | [search][search-change] | Minor change in functionality, but not new. |
|
||||
| `chore` | [search][search-chore] | Cleanup work, maintenance, without change in functionality. |
|
||||
| `chore` | [search][search-chore] | Cleanup work, without change in functionality. |
|
||||
| `docs` | [search][search-docs] | Relating to any type of documentation. |
|
||||
| `feat` | [search][search-feat] | Feature requests. |
|
||||
| `fix` | [search][search-fix] | For PRs only: a bug fix, corresponds to issue label `bug`. |
|
||||
| `maint` | [search][search-maint] | Maintenance work -- continuous integration, build scripts, infrastructure. |
|
||||
| `question` | [search][search-question] | Questions more than bug reports or feature requests (e.g. how do I do X). [**Usually better on the Keyman Community**](https://community.software.sil.org/c/keyman) |
|
||||
| `refactor` | [search][search-refactor] | Code reorganization and refactoring, without change in functionality. |
|
||||
| `spec` | [search][search-spec] | Issues which are specifications for a large scale feature. |
|
||||
|
|
@ -443,6 +444,7 @@ These labels also include sublabels, such as `windows/config/`.
|
|||
[search-docs]: https://github.com/keymanapp/keyman/labels/docs
|
||||
[search-feat]: https://github.com/keymanapp/keyman/labels/feat
|
||||
[search-fix]: https://github.com/keymanapp/keyman/labels/fix
|
||||
[search-maint]: https://github.com/keymanapp/keyman/labels/maint
|
||||
[search-question]: https://github.com/keymanapp/keyman/labels/question
|
||||
[search-spec]: https://github.com/keymanapp/keyman/labels/spec
|
||||
[search-style]: https://github.com/keymanapp/keyman/labels/style
|
||||
|
|
|
|||
433
HISTORY.md
433
HISTORY.md
|
|
@ -1,5 +1,310 @@
|
|||
# Keyman Version History
|
||||
|
||||
## 19.0.63 alpha 2025-06-12
|
||||
|
||||
* maint(web): add some more arguments for web release build script (#14167)
|
||||
* maint(developer): use double quotes so that variable gets replaced (#14168)
|
||||
* chore(deps): bump brace-expansion from 2.0.1 to 2.0.2 in /developer/src/server/src/win32/trayicon/addon-src (#14165)
|
||||
|
||||
## 19.0.62 alpha 2025-06-11
|
||||
|
||||
* maint(developer): export environment variables (#14157)
|
||||
* maint(web): use path when calling powershell script (#14156)
|
||||
* maint(resources): fix regression on mac triggering builds (#14155)
|
||||
|
||||
## 19.0.61 alpha 2025-06-10
|
||||
|
||||
* chore(developer): extend unit test timeout for getLastGitCommitDate (#14147)
|
||||
* fix(common): Use zip.inc.sh for common test keyboards (#14145)
|
||||
* maint(developer): add docker image to build developer node modules (#14058)
|
||||
|
||||
## 19.0.60 alpha 2025-06-06
|
||||
|
||||
* maint(developer): allow to build locally on Linux (#14059)
|
||||
|
||||
## 19.0.59 alpha 2025-06-05
|
||||
|
||||
* chore(deps): bump multer from 2.0.0 to 2.0.1 (#14127)
|
||||
* maint(web): fix working directory for zipping artifacts for Web release (#14128)
|
||||
* chore(linux): Update debian changelog (#14119)
|
||||
* maint(web): improve TC build script for Keyman Web/Test (#14051)
|
||||
* maint(developer): move TC configuration for Keyman Developer to scripts (#14052)
|
||||
|
||||
## 19.0.58 alpha 2025-06-04
|
||||
|
||||
* feat(developer): update strs compiler to collect context (#14064)
|
||||
* feat(developer): line numbers for UsetCompiler, others (#14090)
|
||||
* feat(developer): remaining line numbers for tran/bksp compilers (#14097)
|
||||
* feat(developer): ldml: update errors for unparseable reorder (#14098)
|
||||
* chore(developer): ldml: messages cleanup (#14100)
|
||||
* maint(android): Create "archive" builder step to prep release artifacts (#14093)
|
||||
* maint(web): move TC configuration for Web to script (#14049)
|
||||
|
||||
## 19.0.57 alpha 2025-06-03
|
||||
|
||||
* fix(windows): change from error to breadcrumb and log (#14069)
|
||||
* maint(mac): make make-km-dmg.sh less quiet (#14105)
|
||||
|
||||
## 19.0.56 alpha 2025-06-02
|
||||
|
||||
* maint(ios): Use zip.inc.sh to prep release artifacts (#13919)
|
||||
* maint(linux): update to new version of gha-ubuntu-packaging (#14094)
|
||||
* chore(linux): add Python TC test runner (#14062)
|
||||
|
||||
## 19.0.55 alpha 2025-05-31
|
||||
|
||||
* maint(linux): `sudo` not required for removing temporary files (#14086)
|
||||
* maint(linux): update to new version of gha-ubuntu-packaging (#14089)
|
||||
|
||||
## 19.0.54 alpha 2025-05-30
|
||||
|
||||
* maint(linux): move TC build scripts to `resources/teamcity/linux` (#14061)
|
||||
|
||||
## 19.0.53 alpha 2025-05-29
|
||||
|
||||
* fix(developer): ensure that kmc doesn't skip validate phase of kmc-ldml (#14068)
|
||||
|
||||
## 19.0.52 alpha 2025-05-28
|
||||
|
||||
* feat(developer): line numbers for tran compiler (#14037)
|
||||
* feat(developer): add line numbers to disp compiler (#14048)
|
||||
* feat(developer): line numbers for layr compiler (#14050)
|
||||
* feat(developer): line numbers for LocaCompiler (#14054)
|
||||
* fix(common): properly use newly installed node version (#14057)
|
||||
* maint(common): update build coordinator and labels for `resources/teamcity` changes (#14047)
|
||||
|
||||
## 19.0.51 alpha 2025-05-27
|
||||
|
||||
* maint: add stable-19.0 triggers (#14043)
|
||||
* maint: add empty 'scripts' tag to package.json to silence warning (#14044)
|
||||
* fix(linux): fix version variable references in kmconfig (#14032)
|
||||
|
||||
## 19.0.50 alpha 2025-05-26
|
||||
|
||||
* chore(web): mark async methods in UI components (#14034)
|
||||
|
||||
## 19.0.49 alpha 2025-05-25
|
||||
|
||||
* feat(developer): revamp line numbers per design doc (#14016)
|
||||
* docs(developer): add compiler message internal documentation (#14025)
|
||||
* feat(developer): add line numbers to vars compiler (#14036)
|
||||
|
||||
## 19.0.48 alpha 2025-05-23
|
||||
|
||||
* maint(web): upgrade Sentry to 8.55.0 (#14030)
|
||||
|
||||
## 19.0.47 alpha 2025-05-22
|
||||
|
||||
* fix(windows): only breadcrumb unexpected state on first run (#13984)
|
||||
* maint: change builder_completion script to a .inc.sh (#14007)
|
||||
* fix(windows): skip sending handle kmshell events to upgrade state machine for keyboard install modes (#13989)
|
||||
* fix(windows): fix sentry error message reporting (#14027)
|
||||
|
||||
## 19.0.46 alpha 2025-05-21
|
||||
|
||||
* docs(common): update README with number of languages and keyboards (#14023)
|
||||
|
||||
## 19.0.45 alpha 2025-05-21
|
||||
|
||||
* maint(linux): use correct syntax to define local variables in script (#14021)
|
||||
* maint(developer): update multer to v2.0.0 (#14012)
|
||||
|
||||
## 19.0.44 alpha 2025-05-21
|
||||
|
||||
* feat(android): log active keyboard, model IDs with reported errors (#13983)
|
||||
* fix(windows): rename Enter and Exit methods TState (#13920)
|
||||
* maint: update macOS environment setup, related documentation (#13979)
|
||||
* chore(deps): bump multer from 1.4.5-lts.1 to 2.0.0 (#13982)
|
||||
* feat(ios): log active keyboard, model IDs with reported errors (#13987)
|
||||
* maint(linux): add quilt to release build configuration (#13986)
|
||||
* chore(ios): update FirstVoices AppIcon (#13976)
|
||||
* docs(developer): add security note to Upload documentation (#14015)
|
||||
* fix(android): Check network access before trying to download keyboard (#13978)
|
||||
|
||||
## 19.0.43 alpha 2025-05-20
|
||||
|
||||
* chore(ios): FirstVoices certificate update (#13991)
|
||||
* fix(linux): configurable path in `.service` file when using basu (#13980)
|
||||
|
||||
## 19.0.42 alpha 2025-05-20
|
||||
|
||||
* maint(linux): add `--no-werror` option to not report warnings as errors (#13988)
|
||||
|
||||
## 19.0.41 alpha 2025-05-19
|
||||
|
||||
* fix(web): inspectable test-script mode should not be auto-enabled in local-env tests (#13895)
|
||||
* maint(common): evaluate and apply npm audit fix (without forced changes) (#13897)
|
||||
* maint: update mocha (#13899)
|
||||
* maint: update @actions/github + @octokit references (#13900)
|
||||
* maint(common): update fast-json-patch to ^3.1.1 (#13901)
|
||||
* change(web): cancel flicks when both returning to and releasing at original tap location (#13683)
|
||||
* fix(web): empty layout fontSize property should default to 1em (#13959)
|
||||
* maint(linux): fix release build to run all tests except integration tests (#13968)
|
||||
|
||||
## 19.0.40 alpha 2025-05-17
|
||||
|
||||
* maint(common): Add zip.inc.sh for cross-platform zipping (#13812)
|
||||
|
||||
## 19.0.39 alpha 2025-05-16
|
||||
|
||||
* chore(mac,windows): Update Crowdin strings for Italian (#13871)
|
||||
* refactor(web): rename generic type variables (#13930)
|
||||
* maint(linux): properly fallback to `VERSION` in deb-packaging (#13961)
|
||||
* maint(linux): update gha-ubuntu-packaging dependency (#13964)
|
||||
* fix(linux): use correct header guard define in OrderedOutputDevice.h (#13962)
|
||||
* maint(linux): don't include `dockerbuild` log files (#13965)
|
||||
* maint(linux): update GHA dependencies for Linux package builds (#13966)
|
||||
|
||||
## 19.0.38 alpha 2025-05-15
|
||||
|
||||
* chore(android): Update FirstVoices launcher icon and red theme (#13907)
|
||||
* feat(developer): add more line number issues for KeysCompiler (#13915)
|
||||
* feat(developer): add line number for MetaCompiler (#13916)
|
||||
* maint(linux): address comments from Debian package review (#13904)
|
||||
* maint(linux): add Questing to launchpad package builds (#13910)
|
||||
* maint(linux): fix logging in `deb-packaging.sh` (#13912)
|
||||
* maint(linux): remove temporary files created during dependency installation (#13913)
|
||||
* maint(common): move TC build configs for Linux to scripts (#13754)
|
||||
* fix(developer): remove ngrok binary at build time (#13847)
|
||||
* chore(linux): Update debian changelog (#13889)
|
||||
* refactor(web): rename `HardKeyboard` to `HardKeyboardBase` (#13929)
|
||||
* refactor(web): rename base `KeymanEngine` to `KeymanEngineBase` (#13942)
|
||||
|
||||
## 19.0.37 alpha 2025-05-14
|
||||
|
||||
* maint(linux): remove generated file that got accidentally committed (#13902)
|
||||
* maint(linux): remove check for patched ibus from `meson.build` (#13909)
|
||||
* maint(common): report builder errors to stderr (#13882)
|
||||
|
||||
## 19.0.36 alpha 2025-05-13
|
||||
|
||||
* feat(developer): line numbers for XML parsing and kmc-ldml (#13375)
|
||||
* maint(android): Update to Java 21 and Gradle dependencies (#13858)
|
||||
* maint(linux): improve getting PR# in `upload-to-debian.sh` (#13890)
|
||||
* fix(linux): fallback to `VERSION` if `KEYMAN_VERSION` isn't set during package build (#13891)
|
||||
* maint(common): move and document `builder_is_ci_*` functions (#13892)
|
||||
* maint(android): use new variable name `KEYMAN_TIER` (#13898)
|
||||
* fix(mac): handle PackageInfo section in kmp.inf file (#13876)
|
||||
|
||||
## 19.0.35 alpha 2025-05-12
|
||||
|
||||
* maint(common): add two more functions to detect if running on CI (#13869)
|
||||
* maint(common): use unique names for Keyman version variables (#13854)
|
||||
* maint(common): use new `builder_is_running_on_*` functions (#13875)
|
||||
* maint(common): remove obsolete code from docker-images `run.sh` (#13879)
|
||||
* chore(mac): remove obsolete key processing code (#13848)
|
||||
|
||||
## 19.0.34 alpha 2025-05-08
|
||||
|
||||
* docs(common): update `builder_echo` documentation for TC blocks (#13855)
|
||||
* fix(windows): add breadcrumb to download failures (#13826)
|
||||
* fix(web): sustain active batched-layout mode when keyboard is switched (#13860)
|
||||
* maint(common): remove obsolete code from docker-images `build.sh` (#13861)
|
||||
* maint(common): output start/end messages if not running on TC (#13868)
|
||||
|
||||
## 19.0.33 alpha 2025-05-07
|
||||
|
||||
* maint(common): automatically set --debug option for local-environment builder-script uses (#13827)
|
||||
* docs(web): add a Web engine keystroke lifecycle internal doc (#13759)
|
||||
* maint(common): use function to detect if running on TC (#13844)
|
||||
* docs(common): document new `builder_is_running_on_teamcity` function (#13852)
|
||||
|
||||
## 19.0.32 alpha 2025-05-06
|
||||
|
||||
* change(web): replace USVString with string in predictive-text engine (#13785)
|
||||
* chore(web): replace --ci flag with builder_is_ci_build (#13819)
|
||||
* maint(web): simplify worker-main test.sh (#13820)
|
||||
* change(web): lint kmwstring web-utility (#13800)
|
||||
* fix(web): fix extraction of gesture-engine fixture used in DOM-based unit tests (#13805)
|
||||
* fix(web): add robustness for bad touch-layout fontsize specs (#13774)
|
||||
* fix(web): fix var declaration affected by linter strictness + length-style fix (#13839)
|
||||
* chore(ios): Update inuktitut_pirurvik to 1.4.1 (#13840)
|
||||
* chore(common): override check when running on TC (#13779)
|
||||
* change(linux): add ICU dependency needed to build on Arch Linux (#13842)
|
||||
* maint(common): add support for TC blocks (#13810)
|
||||
|
||||
## 19.0.31 alpha 2025-05-05
|
||||
|
||||
* fix(mac): add version metadata after building tests (#13818)
|
||||
* maint(common): remove `eslint:recommended` configuration for .ts (#13825)
|
||||
* maint(common): Update write_download_info() to be cross-platform (#13813)
|
||||
* change(ios): limit reports about devices without predefined scaling entries (#13806)
|
||||
* change(web): lint engine/common/web-utils (#13797)
|
||||
* chore(web): replace kmwFromCharCode with its ES6 equivalent (#13716)
|
||||
* chore(web): add unit tests for SMP-aware string-handling helper methods (#13719)
|
||||
* refactor(web): refactor string-helper library to eliminate its module side-effect (#13726)
|
||||
|
||||
## 19.0.30 alpha 2025-05-02
|
||||
|
||||
* chore(android): Use `builder_is_ci_build` rather than `--ci` flag (#13772)
|
||||
* docs: add `--deps` flags and move builder.md into /docs (#13815)
|
||||
* chore(web): improve clean actions (#13804)
|
||||
* fix(ios): restore keyboard-scale settings for older, still-supported iOS devices (#13773)
|
||||
* maint(web): merge LMLayer CI build config with standard Web CI build config (#13807)
|
||||
* maint(core): batch build kmx in tests for performance (#13795)
|
||||
* maint(common): cleanup meson versioning (#13796)
|
||||
* maint(common): test imported resource versions (#13803)
|
||||
|
||||
## 19.0.29 alpha 2025-04-30
|
||||
|
||||
* change(web): enable linting for Keyman Engine for Web modules (#13787)
|
||||
* fix(web): reconnect unit tests for low-level web utility classes/methods (#13714)
|
||||
* fix(android): Change Alert Dialog instead of Toast if package missing languages (#13786)
|
||||
* maint(common): remove platform advocates from CODEOWNERS (#13801)
|
||||
* chore(common): allow to run tests in virtual environment (#13793)
|
||||
* chore: increase linter strictness (#13788)
|
||||
|
||||
## 19.0.28 alpha 2025-04-29
|
||||
|
||||
* chore(common): Update dependencies in crowdin GitHub action (#13775)
|
||||
* chore: additional tweaks to scopes/labels (#13765)
|
||||
* chore(common): rename `chore` GH label to `maint` (#13780)
|
||||
* change(linux): add link to issue (#13778)
|
||||
|
||||
## 19.0.27 alpha 2025-04-28
|
||||
|
||||
* chore: update labels for v19 (#13744)
|
||||
|
||||
## 19.0.26 alpha 2025-04-24
|
||||
|
||||
* chore: merge beta version 18.0.235 history to master (#13735)
|
||||
* chore(linux): Update debian changelog (#13738)
|
||||
* chore: comment out CODEOWNERS (#13739)
|
||||
* chore(linux): add a stub unit test to allow successful coverage reporting (#13740)
|
||||
|
||||
## 19.0.25 alpha 2025-04-22
|
||||
|
||||
* chore: merge beta to master (pre-release prep) (#13730)
|
||||
|
||||
## 19.0.24 alpha 2025-04-21
|
||||
|
||||
* build(deps): bump koa from 2.15.3 to 2.16.1 (#13694)
|
||||
* chore: merge beta into master B18S5 (#13712)
|
||||
|
||||
## 19.0.23 alpha 2025-04-07
|
||||
|
||||
* chore(web): remove dead methods regarding keyboard state (#13671)
|
||||
* chore(linux): Update debian changelog (#13675)
|
||||
|
||||
## 19.0.22 alpha 2025-04-04
|
||||
|
||||
* build(deps): bump tar-fs and puppeteer-core (#13661)
|
||||
|
||||
## 19.0.21 alpha 2025-04-03
|
||||
|
||||
* chore: use explicit `node:` prefix for node imports (#13650)
|
||||
* refactor(developer): rename developer/web/utils/common-messages.ts to developer-utils-messages.ts (#13653)
|
||||
* refactor(developer): move sentry and developer options into console apps (#13654)
|
||||
* refactor(developer): consolidate project loader (#13656)
|
||||
|
||||
## 19.0.20 alpha 2025-04-01
|
||||
|
||||
* fix(android): move responsibility for setting keyboard height preference into `applyKeyboardHeight()` (#13578)
|
||||
|
||||
## 19.0.19 alpha 2025-03-31
|
||||
|
||||
* chore: merge beta to master B18S4 (#13606)
|
||||
|
||||
## 19.0.18 alpha 2025-03-25
|
||||
|
||||
* chore(developer): improve ldml code coverage (#13516)
|
||||
|
|
@ -80,6 +385,134 @@
|
|||
* refactor(windows): rename `TKeymanMutex.MutexOwned` to `TakeOwnership` and add `ReleaseOwnership` (#13168)
|
||||
* chore: increment to alpha 19.0 (#13187)
|
||||
|
||||
## 18.0.238 stable 2025-06-04
|
||||
|
||||
* fix(developer): ldml: make sure .run() calls compile() for validation (#14071)
|
||||
* maint(linux): fix typo of temporary dependency package (#14085)
|
||||
* maint(linux): update to new version of gha-ubuntu-packaging (#14096)
|
||||
* maint(mac): make make-km-dmg.sh less quiet (#14106)
|
||||
|
||||
## 18.0.237 stable 2025-05-30
|
||||
|
||||
* maint(android): Update FirstVoices launcher icon and red theme (#13917)
|
||||
* fix(web): empty layout fontSize property should default to 1em (#13960)
|
||||
* fix(linux): use correct header guard define in OrderedOutputDevice.h (#13963)
|
||||
* chore(linux): Update debian changelog (#13888)
|
||||
* fix(mac): handle PackageInfo section in kmp.inf file (#13957)
|
||||
* feat(android): log active keyboard, model IDs with reported errors (#14003)
|
||||
* chore(ios): FirstVoices certificate update (#14005)
|
||||
* feat(ios): log active keyboard, model IDs with reported errors (#14006)
|
||||
* fix(linux): configurable path in `.service` file when using basu (#13999)
|
||||
* maint(linux): add `--no-werror` option to not report warnings as errors (#14000)
|
||||
* fix(windows): use json file name against cache folder and ename Enter and Exit methods for TState Object (#14010)
|
||||
* chore(ios): update FirstVoices AppIcon (#14011)
|
||||
* maint: change builder_completion script to a .inc.sh (#14008)
|
||||
* fix(windows): only breadcrumb unexpected state on first run (#14026)
|
||||
* fix(windows): skip sending handle kmshell events to upgrade state machine for keyboard install modes (#14028)
|
||||
* fix(windows): fix sentry error message reporting (#14029)
|
||||
|
||||
## 18.0.236 stable 2025-05-12
|
||||
|
||||
* chore(linux): Update debian changelog (#13737)
|
||||
* chore(linux): add a stub unit test to allow successful coverage reporting (#13741)
|
||||
* fix(android): Use Alert Dialog if keyboard pkg missing languages (#13802)
|
||||
* maint(web): merge LMLayer CI build config with standard Web CI build config (#13808)
|
||||
* fix(ios): restore keyboard-scale settings for older, still-supported iOS devices (#13817)
|
||||
* change(ios): limit reports about devices without predefined scaling entries (#13828)
|
||||
* chore(ios): Update inuktitut_pirurvik to 1.4.1 (#13841)
|
||||
* fix(web): add robustness for bad touch-layout fontsize specs (#13838)
|
||||
* change(linux): add ICU dependency needed to build on Arch Linux (#13843)
|
||||
* fix(mac): add version metadata after building tests (#13853)
|
||||
* fix(web): sustain active batched-layout mode when keyboard is switched (#13863)
|
||||
* fix(developer): remove ngrok binary at build time (#13873)
|
||||
* maint(common): apply new codeowners from master (#13874)
|
||||
* chore(mac,windows): Update Crowdin strings for Italian (#13872)
|
||||
|
||||
## 18.0.234 beta 2025-04-22
|
||||
|
||||
* fix(android): Require RELEASE_OEM env vars to build FirstVoices Android (#13725)
|
||||
|
||||
## 18.0.233 beta 2025-04-21
|
||||
|
||||
* chore: cleanup kps.xsd version typos (#13670)
|
||||
* fix(android): refresh system keyboard banner on reload (#13702)
|
||||
* chore(ios): update keyboard-size data for current iOS devices (#13697)
|
||||
* fix(ios): ensure update notification does not go translucent/transparent (#13698)
|
||||
* fix(ios): resummon keyboard when keyboard picker is dismissed (#13701)
|
||||
* fix(web): match banner font scaling to osk font scaling (#13646)
|
||||
* docs(common): Document Keyman website server-side dependencies (#13642)
|
||||
* docs(windows): update FAQ (#13708)
|
||||
|
||||
## 18.0.232 beta 2025-04-10
|
||||
|
||||
* fix(android): Downgrade UnknownHostException error to info (#13692)
|
||||
* change(web): add unique classname to mobile-device page-trailer element (#13632)
|
||||
* chore(android,mac,windows): Update crowdin strings for Spanish Latin America (#13691)
|
||||
|
||||
## 18.0.231 beta 2025-04-09
|
||||
|
||||
* docs(android): Document default keyboard height for xxxhdpi devices (#13673)
|
||||
* fix(ios): allow swipe-dismissal of Settings to be cancelled (#13686)
|
||||
* fix(ios): do not show notification for downloaded keyboard when showing its installer (#13687)
|
||||
* fix(ios): restore banner-hiding mechanism for keyboard calibration tool (#13689)
|
||||
|
||||
## 18.0.230 beta 2025-04-08
|
||||
|
||||
* docs(web): documentation for touch-keyboard gesture models (#13659)
|
||||
|
||||
## 18.0.229 beta 2025-04-07
|
||||
|
||||
* fix(ios): ensure keyboard height is set when engine settings view is used in a NavigationController (#13643)
|
||||
* chore(android,mac,windows): update Crowdin strings for Czech (#13680)
|
||||
* chore(android,mac,windows): update Crowdin strings for Khmer (#13681)
|
||||
* chore(linux): Update debian changelog (#13674)
|
||||
|
||||
## 18.0.228 beta 2025-04-04
|
||||
|
||||
* fix(ios): prevent re-display of keyboard when re-entering app to its menus (#13630)
|
||||
* fix(ios): slide dismissal of keyboard-height adjuster will properly resize the keyboard (#13631)
|
||||
* docs(web): improve section on motivation for gesture input serialization (#13652)
|
||||
* fix(linux): fix crash if kmp doesn't have name field (#13648)
|
||||
* chore(web): improve error logging in predictive-text worker message validation (#13660)
|
||||
* fix(android): Adjust keyboard and banner heights for mdpi and hdpi devices (#13651)
|
||||
* fix(android): adjust keyboard and banner height for xhdpi portrait (#13655)
|
||||
* fix(android): Adjust keyboard and banner height for 7" tablet landscape (#13667)
|
||||
* fix(android): Adjust keyboard height for 10" tablet landscape (#13668)
|
||||
|
||||
## 18.0.227 beta 2025-04-03
|
||||
|
||||
* fix(developer): remove redundant keyboard fields from .kps (#13600)
|
||||
* fix(developer): remove redundant Name and RTL fields from .kps `LexicalModel` (#13640)
|
||||
* fix(mac): reevaluate API compliance for each change in context (#13550)
|
||||
* fix(android): Move responsibility for setting keyboard height preference (#13635)
|
||||
* fix(android): Add back button to "Adjust Keyboard Height "menu (#13645)
|
||||
* fix(linux): allow unhandled keys to pass through to compliant apps (#13625)
|
||||
|
||||
## 18.0.226 beta 2025-04-02
|
||||
|
||||
* docs(web): document internals for gesture modeling and processing (#13587)
|
||||
* docs(web): document input-serialization aspects of gesture processing (#13597)
|
||||
* fix(android): Add dimensions for 320+dpi phones in landscape (#13592)
|
||||
* chore(common): Update crowdin strings for Mon (#13595)
|
||||
* docs(linux): add function headers for some of the engine methods (#13637)
|
||||
|
||||
## 18.0.225 beta 2025-04-01
|
||||
|
||||
* fix(web): remove extra px offset from last OSK row (#13621)
|
||||
* fix(developer): add special handling for 'und' in kmc-keyboard-info (#13622)
|
||||
* chore(mac,windows): Update Crowdin strings for Italian (#13594)
|
||||
* change(ios): prevent file erasure during copyWithOverwrite error state (#13548)
|
||||
* fix(ios): uninstalls keyboards upon failure to load (#13549)
|
||||
* refactor(linux): remove warning if no custom keyboards exist (#13624)
|
||||
|
||||
## 18.0.224 beta 2025-03-31
|
||||
|
||||
* fix(windows): reload right modifier key option (#13585)
|
||||
|
||||
## 18.0.223 beta 2025-03-29
|
||||
|
||||
* chore(developer): improve kmc-ldml 'invalid version' message (#13602)
|
||||
|
||||
## 18.0.222 beta 2025-03-28
|
||||
|
||||
* fix(android): Handle banner overrides independently when device is locked and unlocked (#13546)
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
# License
|
||||
|
||||
Copyright (c) 2017-2024 SIL Global. All rights reserved.
|
||||
Copyright (c) 2017-2025 SIL Global. All rights reserved.
|
||||
|
||||
Licensed under the MIT License.
|
||||
|
||||
[Keyman for Linux](./linux) is licensed under the MIT License apart from [ibus-kmfl](./linux/ibus-kmfl) which is licensed under the GNU General Public License as published by the Free Software Foundation; either [version 2](./linux/ibus-kmfl/COPYING) of the License, or (at your option) any later version.
|
||||
|
||||
---
|
||||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2017-2024 SIL Global
|
||||
Copyright (c) 2017-2025 SIL Global
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -28,4 +26,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||

|
||||
|
||||
[Keyman](https://keyman.com) makes it possible for you to type in any language on Windows, macOS, Linux, iPhone, iPad, Android tablets and phones, and even instantly in your web browser. Create keyboard layouts with Keyman Developer and share them with the community in the [keyboards repository](https://github.com/keymanapp/keyboards). The [Keyman Community](https://community.software.sil.org/c/keyman) have already contributed keyboard layouts for over 2,000 languages!
|
||||
[Keyman](https://keyman.com) makes it possible for you to type in any language
|
||||
on Windows, macOS, Linux, iPhone, iPad, Android tablets and phones, and even
|
||||
instantly in your web browser. Create keyboard layouts with Keyman Developer and
|
||||
share them with the community in the [keyboards
|
||||
repository](https://github.com/keymanapp/keyboards). The [Keyman
|
||||
Community](https://community.software.sil.org/c/keyman) have so far contributed
|
||||
well over 1,000 keyboard layouts for over 2,500 languages!
|
||||
|
||||
# License
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
19.0.19
|
||||
19.0.64
|
||||
3
android/.gitignore
vendored
3
android/.gitignore
vendored
|
|
@ -57,6 +57,9 @@ KMAPro/**/assets/*.kmp
|
|||
# Play Store release notes (copied from whatsnew.md)
|
||||
KMAPro/kMAPro/src/main/play/release-notes/**/*.txt
|
||||
|
||||
# Release artifacts
|
||||
upload/
|
||||
|
||||
# Eclipse files
|
||||
.project
|
||||
.settings/
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ function generateReleaseNotes() {
|
|||
# Copy release notes for Gradle Play Publisher to upload
|
||||
# Reference: https://github.com/Triple-T/gradle-play-publisher#uploading-release-notes
|
||||
#
|
||||
local PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/$TIER.txt"
|
||||
if [ $TIER = "stable" ]; then
|
||||
local PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/${KEYMAN_TIER}.txt"
|
||||
if [ $KEYMAN_TIER = "stable" ]; then
|
||||
PLAY_RELEASE_NOTES="$KEYMAN_ROOT/android/KMAPro/kMAPro/src/main/play/release-notes/en-US/default.txt"
|
||||
fi
|
||||
builder_heading "Generating Play Store release notes to $PLAY_RELEASE_NOTES"
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ buildscript {
|
|||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'com.android.tools.build:gradle:8.9.2'
|
||||
// sentry-android-gradle-plugin 2.1.5+ requires AGP 7.0
|
||||
classpath 'io.sentry:sentry-android-gradle-plugin:4.6.0'
|
||||
classpath 'name.remal:gradle-plugins:1.5.0'
|
||||
classpath 'name.remal:gradle-plugins:1.9.2'
|
||||
|
||||
// From jcenter() which was deprecated August 2024
|
||||
// https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-help.inc.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-download-resources.sh"
|
||||
|
||||
|
|
@ -28,7 +29,6 @@ builder_describe "Builds Keyman for Android app." \
|
|||
"build" \
|
||||
"test Runs lint and unit tests." \
|
||||
"publish Publishes symbols to Sentry and the APK to the Play Store." \
|
||||
"--ci Don't start the Gradle daemon. For CI" \
|
||||
"--upload-sentry Upload to sentry"
|
||||
|
||||
# parse before describe_outputs to check debug flags
|
||||
|
|
@ -37,32 +37,32 @@ builder_parse "$@"
|
|||
if builder_is_debug_build; then
|
||||
builder_heading "### Debug config ####"
|
||||
CONFIG="debug"
|
||||
BUILD_FLAGS="assembleDebug -x lint -x test"
|
||||
BUILD_FLAGS="assembleDebug -x lintDebug -x testDebug"
|
||||
TEST_FLAGS="-x assembleDebug lintDebug testDebug"
|
||||
fi
|
||||
|
||||
builder_describe_outputs \
|
||||
configure /android/KMAPro/kMAPro/libs/keyman-engine.aar \
|
||||
build /android/KMAPro/kMAPro/build/outputs/apk/$CONFIG/keyman-${VERSION}.apk
|
||||
build /android/KMAPro/kMAPro/build/outputs/apk/$CONFIG/keyman-${KEYMAN_VERSION}.apk
|
||||
|
||||
#### Build
|
||||
|
||||
|
||||
# Parse args
|
||||
|
||||
if builder_has_option --ci; then
|
||||
if builder_is_ci_build; then
|
||||
DAEMON_FLAG=--no-daemon
|
||||
fi
|
||||
|
||||
#### Build action definitions ####
|
||||
|
||||
function makeLocalSentryRelease() {
|
||||
echo "Making a Sentry release for tag $VERSION_GIT_TAG"
|
||||
echo "Making a Sentry release for tag $KEYMAN_VERSION_GIT_TAG"
|
||||
sentry-cli upload-dif -p keyman-android --include-sources
|
||||
sentry-cli releases -p keyman-android files $VERSION_GIT_TAG upload-sourcemaps ./
|
||||
sentry-cli releases -p keyman-android files $KEYMAN_VERSION_GIT_TAG upload-sourcemaps ./
|
||||
|
||||
echo "Finalizing release tag $VERSION_GIT_TAG"
|
||||
sentry-cli releases finalize "$VERSION_GIT_TAG"
|
||||
echo "Finalizing release tag $KEYMAN_VERSION_GIT_TAG"
|
||||
sentry-cli releases finalize "$KEYMAN_VERSION_GIT_TAG"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
# AGP 8.0 generates R classes for resources defined in the current module only.
|
||||
android.nonTransitiveRClass=false
|
||||
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -20,6 +20,15 @@ android {
|
|||
noCompress "kmp"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.tavultesoft.kmapro"
|
||||
minSdkVersion 21
|
||||
|
|
@ -29,11 +38,11 @@ android {
|
|||
//dumpProperties(project) // Use this to dump all external properties for debugging TeamCity integration
|
||||
//println "===END DUMP==="
|
||||
|
||||
// VERSION strings from version.gradle
|
||||
versionCode VERSION_CODE as Integer
|
||||
versionName VERSION_NAME
|
||||
buildConfigField 'String', 'VERSION_ENVIRONMENT', '"'+VERSION_ENVIRONMENT+'"'
|
||||
buildConfigField 'String', 'VERSION_GIT_TAG', '"'+VERSION_GIT_TAG+'"'
|
||||
// KEYMAN_VERSION strings from version.gradle
|
||||
versionCode KEYMAN_VERSION_CODE as Integer
|
||||
versionName KEYMAN_VERSION_NAME
|
||||
buildConfigField 'String', 'KEYMAN_VERSION_ENVIRONMENT', '"'+KEYMAN_VERSION_ENVIRONMENT+'"'
|
||||
buildConfigField 'String', 'KEYMAN_VERSION_GIT_TAG', '"'+KEYMAN_VERSION_GIT_TAG+'"'
|
||||
}
|
||||
|
||||
String env_release_store_file = System.getenv("release_store_file")
|
||||
|
|
@ -77,7 +86,7 @@ android {
|
|||
// - PR builds also have "-test-1234" suffix (where 1234 is PR#)
|
||||
// Gradle sync will nullify these values, so have a fallback
|
||||
String appSuffix = ''
|
||||
String tag = VERSION_TAG ? VERSION_TAG : '-' + tier;
|
||||
String tag = KEYMAN_VERSION_TAG ? KEYMAN_VERSION_TAG : '-' + tier;
|
||||
if (tag.startsWithAny("-beta", "beta")) {
|
||||
appSuffix = ' Beta';
|
||||
} else if (tag.startsWithAny("-alpha", "alpha")) {
|
||||
|
|
@ -88,16 +97,16 @@ android {
|
|||
// -test-PR_NUMBER
|
||||
appSuffix = appSuffix + match.group(1)
|
||||
} else {
|
||||
String environment = VERSION_ENVIRONMENT ? VERSION_ENVIRONMENT : 'local';
|
||||
String environment = KEYMAN_VERSION_ENVIRONMENT ? KEYMAN_VERSION_ENVIRONMENT : 'local';
|
||||
if (environment.matches("local")) {
|
||||
appSuffix = appSuffix + '-' + environment;
|
||||
}
|
||||
}
|
||||
variant.resValue "string", "app_name", 'Keyman' + appSuffix;
|
||||
|
||||
// Adjust output name to "keyman-${VERSION_MD}.apk"
|
||||
// Adjust output name to "keyman-${KEYMAN_VERSION_MD}.apk"
|
||||
variant.outputs.all {
|
||||
outputFileName = "keyman-" + VERSION_MD + ".apk"
|
||||
outputFileName = "keyman-" + KEYMAN_VERSION_MD + ".apk"
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
|
|
@ -156,7 +165,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'com.stepstone.stepper:material-stepper:4.3.1'
|
||||
api(name: 'keyman-engine', ext: 'aar')
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
Log.d(TAG, "Initializing Sentry");
|
||||
SentryAndroid.init(getApplicationContext(), options -> {
|
||||
options.setEnableAutoSessionTracking(false);
|
||||
options.setRelease(com.tavultesoft.kmapro.BuildConfig.VERSION_GIT_TAG);
|
||||
options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.VERSION_ENVIRONMENT);
|
||||
options.setRelease(com.tavultesoft.kmapro.BuildConfig.KEYMAN_VERSION_GIT_TAG);
|
||||
options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.KEYMAN_VERSION_ENVIRONMENT);
|
||||
});
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
|
|
@ -110,9 +110,6 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
@Override
|
||||
public void onInitializeInterface() {
|
||||
super.onInitializeInterface();
|
||||
|
||||
// KeymanWeb reloaded, so we have to pass the banner again
|
||||
BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -272,7 +269,8 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
|
||||
@Override
|
||||
public void onKeyboardShown() {
|
||||
// Do nothing
|
||||
// Refresh banner theme
|
||||
BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
package com.tavultesoft.kmapro;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -34,7 +33,6 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
private static ImageView sampleKeyboard = null;
|
||||
|
||||
// Keeps track of the adjusted keyboard height for saving
|
||||
private static SharedPreferences.Editor editor = null;
|
||||
private static int currentHeight = 0;
|
||||
private static ViewGroup.LayoutParams layoutParams;
|
||||
|
||||
|
|
@ -52,22 +50,19 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
if (actionBar != null) {
|
||||
actionBar.setTitle(null);
|
||||
actionBar.setDisplayUseLogoEnabled(false);
|
||||
actionBar.setDisplayShowHomeEnabled(false);
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
actionBar.setDisplayShowCustomEnabled(true);
|
||||
actionBar.setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.keyman_blue)));
|
||||
}
|
||||
|
||||
TextView adjustKeyboardHeightActivityTitle = (TextView) findViewById(R.id.bar_title);
|
||||
adjustKeyboardHeightActivityTitle.setWidth((int) getResources().getDimension(R.dimen.package_label_width));
|
||||
|
||||
String titleStr = getString(R.string.adjust_keyboard_height);
|
||||
adjustKeyboardHeightActivityTitle.setTextColor(ContextCompat.getColor(this, R.color.ms_white));
|
||||
adjustKeyboardHeightActivityTitle.setText(titleStr);
|
||||
|
||||
SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
editor = prefs.edit();
|
||||
|
||||
sampleKeyboard = (ImageView) findViewById(R.id.sample_keyboard);
|
||||
layoutParams = sampleKeyboard.getLayoutParams();
|
||||
currentHeight = KMManager.getKeyboardHeight(context);
|
||||
|
|
@ -77,9 +72,7 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
resetButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
// Clear the keyboard height preferences to reset
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightPortrait);
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightLandscape);
|
||||
editor.commit();
|
||||
KMManager.applyKeyboardHeight(context, KMManager.KeyboardHeight_Reset);
|
||||
|
||||
// Restore default height
|
||||
currentHeight = KMManager.getKeyboardHeight(context);
|
||||
|
|
@ -107,11 +100,7 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
// Save the currentHeight when the user releases
|
||||
int orientation = KMManager.getOrientation(context);
|
||||
String keyboardHeightKey = (orientation == Configuration.ORIENTATION_LANDSCAPE) ?
|
||||
KMManager.KMKey_KeyboardHeightLandscape : KMManager.KMKey_KeyboardHeightPortrait;
|
||||
editor.putInt(keyboardHeightKey, currentHeight);
|
||||
editor.commit();
|
||||
KMManager.applyKeyboardHeight(context, currentHeight);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -140,11 +129,8 @@ public class AdjustKeyboardHeightActivity extends BaseActivity {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Apply the adjusted height on exit
|
||||
KMManager.applyKeyboardHeight(this, currentHeight);
|
||||
|
||||
super.onBackPressed();
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,14 @@ public class KMPBrowserActivity extends BaseActivity {
|
|||
Intent intent = new Intent(context, MainActivity.class);
|
||||
intent.setData(downloadURI);
|
||||
KMLog.LogBreadcrumb(TAG, "Successful keyboard search now triggering package install", true);
|
||||
startActivity(intent);
|
||||
|
||||
// Verify network access before trying to download
|
||||
if (KMManager.hasConnection(context)) {
|
||||
startActivity(intent);
|
||||
} else {
|
||||
Toast.makeText(context, getString(R.string.no_internet_connection), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finish activity
|
||||
finish();
|
||||
|
|
|
|||
|
|
@ -144,8 +144,8 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
if (KMManager.getMaySendCrashReport()) {
|
||||
SentryAndroid.init(context, options -> {
|
||||
options.setEnableAutoSessionTracking(false);
|
||||
options.setRelease(com.tavultesoft.kmapro.BuildConfig.VERSION_GIT_TAG);
|
||||
options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.VERSION_ENVIRONMENT);
|
||||
options.setRelease(com.tavultesoft.kmapro.BuildConfig.KEYMAN_VERSION_GIT_TAG);
|
||||
options.setEnvironment(com.tavultesoft.kmapro.BuildConfig.KEYMAN_VERSION_ENVIRONMENT);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -440,41 +440,41 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_info:
|
||||
showInfo();
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
showShareDialog();
|
||||
return true;
|
||||
// Android Gradle 8.0 no longer declares resources final, so can't use switch statement here
|
||||
if (item.getItemId() == R.id.action_info) {
|
||||
showInfo();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_share) {
|
||||
showShareDialog();
|
||||
return true;
|
||||
/* Disable Web Browser to investigate Google sign-in
|
||||
case R.id.action_web:
|
||||
} else if ((item.getItemId() == R.id.action_web) {
|
||||
showWebBrowser();
|
||||
return true;*/
|
||||
case R.id.action_text_size:
|
||||
showTextSizeDialog();
|
||||
return true;
|
||||
case R.id.action_clear_text:
|
||||
showClearTextDialog();
|
||||
return true;
|
||||
case R.id.action_get_started:
|
||||
showGetStarted();
|
||||
return true;
|
||||
case R.id.action_settings:
|
||||
showSettings();
|
||||
return true;
|
||||
case R.id.action_update_keyboards:
|
||||
KMManager.getUpdateTool().executeOpenUpdates();
|
||||
// Dismiss icon
|
||||
updateUpdateCountIndicator(0);
|
||||
final MenuItem _keyboardupdate = menu.findItem(R.id.action_update_keyboards);
|
||||
if (_keyboardupdate != null && _keyboardupdate.isVisible()) {
|
||||
_keyboardupdate.setVisible(false);
|
||||
}
|
||||
} else if (item.getItemId() == R.id.action_text_size) {
|
||||
showTextSizeDialog();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_clear_text){
|
||||
showClearTextDialog();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_get_started) {
|
||||
showGetStarted();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_settings) {
|
||||
showSettings();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.action_update_keyboards) {
|
||||
KMManager.getUpdateTool().executeOpenUpdates();
|
||||
// Dismiss icon
|
||||
updateUpdateCountIndicator(0);
|
||||
final MenuItem _keyboardupdate = menu.findItem(R.id.action_update_keyboards);
|
||||
if (_keyboardupdate != null && _keyboardupdate.isVisible()) {
|
||||
_keyboardupdate.setVisible(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -632,7 +632,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
Intent i = new Intent(this, InfoActivity.class);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
startActivity(i);
|
||||
overridePendingTransition(android.R.anim.fade_in, R.anim.hold);
|
||||
overridePendingTransition(android.R.anim.fade_in, com.keyman.engine.R.anim.hold);
|
||||
}
|
||||
|
||||
private void showWebBrowser() {
|
||||
|
|
@ -643,7 +643,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
Intent i = new Intent(this, WebBrowserActivity.class);
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
startActivity(i);
|
||||
overridePendingTransition(android.R.anim.fade_in, R.anim.hold);
|
||||
overridePendingTransition(android.R.anim.fade_in, com.keyman.engine.R.anim.hold);
|
||||
}
|
||||
|
||||
private void showShareDialog() {
|
||||
|
|
|
|||
|
|
@ -116,12 +116,14 @@ public class PackageActivity extends AppCompatActivity implements
|
|||
kmpProcessor.getLanguageCount(pkgInfo, PackageProcessor.PP_KEYBOARDS_KEY, 0) : 0;
|
||||
|
||||
// Sanity check for keyboard packages
|
||||
// Not using showErrorToast to avoid cluttering Sentry with noise
|
||||
if (pkgTarget.equals(PackageProcessor.PP_TARGET_KEYBOARDS)) {
|
||||
if (keyboardCount == 0) {
|
||||
showErrorDialog(context, pkgId, getString(R.string.no_new_touch_keyboards_to_install));
|
||||
return;
|
||||
} else if (languageCount == 0) {
|
||||
showErrorToast(getString(R.string.no_associated_languages));
|
||||
showErrorDialog(context, pkgId, getString(R.string.no_associated_languages));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Ajustar la altura del teclado</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_longpress_delay" comment="Menu action to adjust longpress delay duration">Adjust longpress delay</string>
|
||||
<string name="adjust_longpress_delay" comment="Menu action to adjust longpress delay duration">Ajustar demora de pulsación larga</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">Leyenda de barra espaciadora</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_down" comment="Make longpress delay shorter">Tiempo de retraso más corto</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_longpress_delay_slider" comment="Adjust longpress delay time">Longpress delay time slider</string>
|
||||
<string name="ic_longpress_delay_slider" comment="Adjust longpress delay time">Ajustador del tiempo de retraso de pulsación larga</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_text" comment="Prompt to type in the browser search bar">Buscar o escribir una dirección web</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
plugins {
|
||||
id 'base'
|
||||
id 'com.android.library'
|
||||
id 'name.remal.default-plugins'
|
||||
}
|
||||
|
|
@ -6,20 +7,32 @@ plugins {
|
|||
ext.rootPath = '../../'
|
||||
apply from: "$rootPath/version.gradle"
|
||||
|
||||
base {
|
||||
// Specify library filename keyman-engine-$CONFIG.aar
|
||||
archivesName = "keyman-engine"
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 34
|
||||
namespace "com.keyman.engine"
|
||||
|
||||
buildFeatures {
|
||||
// needed for custom BuildConfigField values in defaultConfig
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
|
||||
// VERSION_CODE and VERSION_NAME from version.gradle but Gradle removes them for libraries
|
||||
buildConfigField "String", "KEYMAN_ENGINE_VERSION_NAME", "\""+VERSION_NAME+"\""
|
||||
buildConfigField "String", "VERSION_ENVIRONMENT", "\""+VERSION_ENVIRONMENT+"\""
|
||||
|
||||
// Sepcify library filename keyman-engine-$CONFIG.aar
|
||||
setProperty("archivesBaseName", "keyman-engine")
|
||||
// KEYMAN_VERSION_CODE and KEYMAN_VERSION_NAME from version.gradle but Gradle removes them for libraries
|
||||
buildConfigField "String", "KEYMAN_ENGINE_VERSION_NAME", "\""+KEYMAN_VERSION_NAME+"\""
|
||||
buildConfigField "String", "KEYMAN_VERSION_ENVIRONMENT", "\""+KEYMAN_VERSION_ENVIRONMENT+"\""
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
@ -36,10 +49,6 @@ android {
|
|||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
// Allows use of a simulated Android API for tests. (Thanks, roboelectric!)
|
||||
includeAndroidResources = true
|
||||
}
|
||||
unitTests.all {
|
||||
testLogging {
|
||||
// May also add "passed", "skipped".
|
||||
|
|
@ -55,17 +64,17 @@ android {
|
|||
|
||||
dependencies {
|
||||
// 1.6.0-rc01 needed to resolve https://issuetracker.google.com/issues/238425626
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
// material:1.7.0 will need Gradle plugin 7.1.0+
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'commons-io:commons-io:2.13.0'
|
||||
implementation 'commons-io:commons-io:2.16.1'
|
||||
implementation 'io.sentry:sentry-android:7.8.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
|
||||
// Robolectric
|
||||
testImplementation 'androidx.test:core:1.5.0'
|
||||
testImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
testImplementation 'org.robolectric:robolectric:4.10.3'
|
||||
testImplementation 'androidx.test.ext:junit:1.2.1'
|
||||
testImplementation 'org.robolectric:robolectric:4.14.1'
|
||||
testImplementation 'androidx.test:core:1.6.1'
|
||||
|
||||
// Generate QR Codes
|
||||
implementation ('com.github.kenglxn.QRGen:android:3.0.1') {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
<title>Keyman</title>
|
||||
<!-- DOMRect only exists as of Chrome 61... thus coming later than ES6. -->
|
||||
<script src="other-polyfills.js"></script>
|
||||
<script src="sentry.min.js"></script>
|
||||
<script src="keyman-sentry.js"></script>
|
||||
<script src="keymanweb-webview.js"></script>
|
||||
<script src="android-host.js"></script>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import android.content.SharedPreferences;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Typeface;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
|
|
@ -273,6 +274,8 @@ public final class KMManager {
|
|||
// will be blocked.
|
||||
private static boolean maySendCrashReport = true;
|
||||
|
||||
private final static String KMEngine_PrefsKey = "KMAPreferences";
|
||||
|
||||
// Keyman public keys
|
||||
public static final String KMKey_ID = "id";
|
||||
public static final String KMKey_Name = "name";
|
||||
|
|
@ -295,8 +298,8 @@ public final class KMManager {
|
|||
public static final String KMKey_KMPInstall_Mode = "kmpInstallMode";
|
||||
public static final String KMKey_KeyboardModified = "lastModified";
|
||||
public static final String KMKey_KeyboardRTL = "rtl";
|
||||
public static final String KMKey_KeyboardHeightPortrait = "keyboardHeightPortrait";
|
||||
public static final String KMKey_KeyboardHeightLandscape = "keyboardHeightLandscape";
|
||||
private static final String KMKey_KeyboardHeightPortrait = "keyboardHeightPortrait";
|
||||
private static final String KMKey_KeyboardHeightLandscape = "keyboardHeightLandscape";
|
||||
|
||||
public static final String KMKey_LongpressDelay = "longpressDelay";
|
||||
|
||||
|
|
@ -345,14 +348,21 @@ public final class KMManager {
|
|||
public static final int KMMinimum_LongpressDelay = 300;
|
||||
public static final int KMMaximum_LongpressDelay = 1500;
|
||||
|
||||
// Default keyboard heights
|
||||
public static final int KeyboardHeight_Reset = 0; // To reset to default, applyKeyboardHeight
|
||||
public static final int KeyboardHeight_Invalid = -1; // If invalid orientation passed to functions
|
||||
public static int KeyboardHeight_Context_Portrait_Default = 0; // Default portrait height
|
||||
public static int KeyboardHeight_Context_Landscape_Default = 0; // Default landscape height
|
||||
public static int KeyboardHeight_Context_Portrait_Current = 0; // Current portrait height
|
||||
public static int KeyboardHeight_Context_Landscape_Current = 0; // Current landscape height
|
||||
|
||||
// Default prediction/correction setting
|
||||
public static final int KMDefault_Suggestion = SuggestionType.PREDICTIONS_WITH_CORRECTIONS.toInt();
|
||||
|
||||
// Keyman files
|
||||
protected static final String KMFilename_KeyboardHtml = "keyboard.html";
|
||||
protected static final String KMFilename_JSEngine = "keymanweb-webview.js";
|
||||
protected static final String KMFilename_JSSentry = "sentry.min.js";
|
||||
protected static final String KMFilename_JSSentryInit = "keyman-sentry.js";
|
||||
protected static final String KMFilename_JSSentry = "keyman-sentry.js";
|
||||
protected static final String KMFilename_AndroidHost = "android-host.js";
|
||||
protected static final String KMFilename_KmwCss = "kmwosk.css";
|
||||
protected static final String KMFilename_KmwGlobeHintCss = "globe-hint.css";
|
||||
|
|
@ -498,6 +508,12 @@ public final class KMManager {
|
|||
migrateCloudKeyboards(appContext);
|
||||
|
||||
CloudDownloadMgr.getInstance().initialize(appContext);
|
||||
|
||||
calculateDefaultKeyboardHeights(context);
|
||||
SharedPreferences prefs = context.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
KeyboardHeight_Context_Portrait_Current = prefs.getInt(KMManager.KMKey_KeyboardHeightPortrait, KMManager.KeyboardHeight_Context_Portrait_Default);
|
||||
KeyboardHeight_Context_Landscape_Current = prefs.getInt(KMManager.KMKey_KeyboardHeightLandscape, KMManager.KeyboardHeight_Context_Landscape_Default);
|
||||
|
||||
}
|
||||
|
||||
public static void executeResourceUpdate(Context aContext)
|
||||
|
|
@ -965,7 +981,6 @@ public final class KMManager {
|
|||
|
||||
copyAsset(context, KMFilename_JSEngine, "", true);
|
||||
copyAsset(context, KMFilename_JSSentry, "", true);
|
||||
copyAsset(context, KMFilename_JSSentryInit, "", true);
|
||||
copyAsset(context, KMFilename_AndroidHost, "", true);
|
||||
copyAsset(context, KMFilename_KmwCss, "", true);
|
||||
copyAsset(context, KMFilename_KmwGlobeHintCss, "", true);
|
||||
|
|
@ -1463,7 +1478,7 @@ public final class KMManager {
|
|||
* @param suggestType SuggestionType
|
||||
*/
|
||||
public static void setMaySuggest(String languageID, SuggestionType suggestType) {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putInt(KMManager.getLanguageAutoCorrectionPreferenceKey(languageID), suggestType.toInt());
|
||||
editor.commit();
|
||||
|
|
@ -1582,7 +1597,7 @@ public final class KMManager {
|
|||
model = model.replaceAll("\"", "'");
|
||||
|
||||
// When entering password field, maySuggest should override to disabled
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
int suggestionPreference = prefs.getInt(getLanguageAutoCorrectionPreferenceKey(languageID), KMDefault_Suggestion);
|
||||
|
||||
RelativeLayout.LayoutParams params;
|
||||
|
|
@ -2213,7 +2228,7 @@ public final class KMManager {
|
|||
*/
|
||||
public static int getLongpressDelay() {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(
|
||||
appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
|
||||
return prefs.getInt(KMKey_LongpressDelay, KMDefault_LongpressDelay);
|
||||
}
|
||||
|
|
@ -2230,7 +2245,7 @@ public final class KMManager {
|
|||
}
|
||||
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(
|
||||
appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putInt(KMKey_LongpressDelay, longpressDelay);
|
||||
editor.commit();
|
||||
|
|
@ -2266,21 +2281,87 @@ public final class KMManager {
|
|||
return bannerHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyboard height in dp for the current device orientation
|
||||
*/
|
||||
public static int getKeyboardHeight(Context context) {
|
||||
int defaultHeight = (int) context.getResources().getDimension(R.dimen.keyboard_height);
|
||||
SharedPreferences prefs = context.getSharedPreferences(context.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
|
||||
int orientation = getOrientation(context);
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return prefs.getInt(KMManager.KMKey_KeyboardHeightPortrait, defaultHeight);
|
||||
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return prefs.getInt(KMManager.KMKey_KeyboardHeightLandscape, defaultHeight);
|
||||
}
|
||||
|
||||
return defaultHeight;
|
||||
return getKeyboardHeight(context, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyboard height in dp for the specified device
|
||||
* orientation
|
||||
*/
|
||||
public static int getKeyboardHeight(Context context, int orientation) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return KMManager.KeyboardHeight_Context_Portrait_Current;
|
||||
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return KMManager.KeyboardHeight_Context_Landscape_Current;
|
||||
} else {
|
||||
return KMManager.KeyboardHeight_Invalid; // Invalid orientation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the keyboard height for the current orientation and store it in SharedPreferences.
|
||||
* If height is KMManager.KeyboardHeight_Reset, remove the stored height for that
|
||||
* orientation, resetting to the default height for the device/orientation.
|
||||
* @param context Context
|
||||
* @param height int - keyboard height in dp
|
||||
*/
|
||||
public static void applyKeyboardHeight(Context context, int height) {
|
||||
int orientation = getOrientation(context);
|
||||
applyKeyboardHeight(context, height, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the keyboard height for the specified orientation and store it in SharedPreferences.
|
||||
* If height is KMManager.KeyboardHeight_Reset, remove the stored height for that orientation.
|
||||
* @param context Context
|
||||
* @param height int - keyboard height in dp
|
||||
* @param orientation int - Configuration.ORIENTATION_PORTRAIT or Configuration.ORIENTATION_LANDSCAPE
|
||||
*/
|
||||
public static void applyKeyboardHeight(Context context, int height, int orientation) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
int defaultHeightForContext = getDefaultKeyboardHeight(orientation);
|
||||
if (orientation != Configuration.ORIENTATION_PORTRAIT && orientation != Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return; // Invalid orientation, do nothing
|
||||
}
|
||||
if (height == KMManager.KeyboardHeight_Reset) {
|
||||
// Passing 0 will reset the stored height for this orientation.
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightLandscape);
|
||||
} else /* (orientation == Configuration.ORIENTATION_PORTRAIT) */{
|
||||
editor.remove(KMManager.KMKey_KeyboardHeightPortrait);
|
||||
}
|
||||
height = defaultHeightForContext;
|
||||
} else {
|
||||
// Applying gating to 50%-200% of default height (following Keyman)
|
||||
if (height < (defaultHeightForContext / 2)) {
|
||||
height = (int) (defaultHeightForContext / 2);
|
||||
} else if (height > (defaultHeightForContext * 2)) {
|
||||
height = (int) (defaultHeightForContext * 2);
|
||||
}
|
||||
|
||||
// Store the new height based on the current orientation
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
editor.putInt(KMManager.KMKey_KeyboardHeightLandscape, height);
|
||||
} else /* (orientation == Configuration.ORIENTATION_PORTRAIT) */ {
|
||||
editor.putInt(KMManager.KMKey_KeyboardHeightPortrait, height);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the height based on the current orientation
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
KeyboardHeight_Context_Landscape_Current = height;
|
||||
} else /* (orientation == Configuration.ORIENTATION_PORTRAIT) */ {
|
||||
KeyboardHeight_Context_Portrait_Current = height;
|
||||
}
|
||||
editor.commit();
|
||||
// Confirm new LayoutParams for in-app or system keyboards
|
||||
if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP)) {
|
||||
InAppKeyboard.loadJavascript(KMString.format("setOskHeight('%s')", height));
|
||||
RelativeLayout.LayoutParams params = getKeyboardLayoutParams();
|
||||
|
|
@ -2293,6 +2374,53 @@ public final class KMManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default keyboard height in dp for the current device
|
||||
* and orientation
|
||||
*/
|
||||
public static int getDefaultKeyboardHeight(Context context) {
|
||||
int orientation = getOrientation(context);
|
||||
return getDefaultKeyboardHeight(orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyboard height in dp for the specified orientation
|
||||
* for the current device
|
||||
*/
|
||||
public static int getDefaultKeyboardHeight(int orientation) {
|
||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return KMManager.KeyboardHeight_Context_Portrait_Default;
|
||||
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return KMManager.KeyboardHeight_Context_Landscape_Default;
|
||||
} else {
|
||||
return KMManager.KeyboardHeight_Invalid; // Invalid orientation
|
||||
}
|
||||
}
|
||||
|
||||
private static void calculateDefaultKeyboardHeights(Context context) {
|
||||
if (isTestMode()) {
|
||||
// Keyboard height not needed for unit tests #13578
|
||||
KeyboardHeight_Context_Portrait_Default = 0;
|
||||
KeyboardHeight_Context_Landscape_Default = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Resources resources = context.getResources();
|
||||
Configuration originalConfig = resources.getConfiguration();
|
||||
|
||||
Configuration newConfig = new Configuration(originalConfig);
|
||||
newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
|
||||
Context newContext = context.createConfigurationContext(newConfig);
|
||||
Resources newResources = newContext.getResources();
|
||||
KeyboardHeight_Context_Portrait_Default = (int) newResources.getDimension(R.dimen.keyboard_height);
|
||||
|
||||
newConfig = new Configuration(originalConfig);
|
||||
newConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
newContext = context.createConfigurationContext(newConfig);
|
||||
newResources = newContext.getResources();
|
||||
KeyboardHeight_Context_Landscape_Default = (int) newResources.getDimension(R.dimen.keyboard_height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the area the window would occupy.
|
||||
* API 30+
|
||||
|
|
@ -2322,7 +2450,7 @@ public final class KMManager {
|
|||
}
|
||||
|
||||
protected static void setPersistentShouldShowHelpBubble(boolean flag) {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(KMManager.KMEngine_PrefsKey, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(KMManager.KMKey_ShouldShowHelpBubble, flag);
|
||||
editor.commit();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.keyman.engine.cloud;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
|
|
@ -60,6 +61,7 @@ public class CloudDownloadMgr{
|
|||
* Append downloadreceiver to the main context.
|
||||
* @param aContext the context
|
||||
*/
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
public synchronized void initialize(Context aContext)
|
||||
{
|
||||
if(isInitialized)
|
||||
|
|
@ -73,6 +75,7 @@ public class CloudDownloadMgr{
|
|||
aContext.registerReceiver(completeListener, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
|
||||
Context.RECEIVER_EXPORTED);
|
||||
} else {
|
||||
// Needs @SuppressLint UnspecifiedRegisterReceiverFlag
|
||||
aContext.registerReceiver(completeListener, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.io.IOException;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public final class Connection {
|
||||
private static final String TAG = "Connection";
|
||||
|
|
@ -103,6 +104,9 @@ public final class Connection {
|
|||
} catch (SocketTimeoutException e) {
|
||||
KMLog.LogBreadcrumb(TAG, "Connection.initialize timeout for: " + originalUrl, true);
|
||||
KMLog.LogInfo(TAG, "SocketTimeoutException");
|
||||
} catch (UnknownHostException e) {
|
||||
KMLog.LogBreadcrumb(TAG, "Connection.initialize could not resolve host: " + originalUrl, true);
|
||||
KMLog.LogInfo(TAG, "UnknownHostException");
|
||||
} catch (Exception e) {
|
||||
KMLog.LogException(TAG, "Initialization failed:", e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,19 @@
|
|||
|
||||
package com.keyman.engine.util;
|
||||
|
||||
import static com.keyman.engine.KMManager.KMKey_LexicalModelID;
|
||||
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.keyman.engine.BaseActivity;
|
||||
import com.keyman.engine.BuildConfig;
|
||||
import com.keyman.engine.KMManager;
|
||||
import com.keyman.engine.util.DependencyUtil;
|
||||
import com.keyman.engine.data.Keyboard;
|
||||
import com.keyman.engine.util.DependencyUtil.LibraryType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.sentry.Breadcrumb;
|
||||
import io.sentry.Sentry;
|
||||
import io.sentry.SentryLevel;
|
||||
|
|
@ -20,19 +24,67 @@ import io.sentry.SentryLevel;
|
|||
public final class KMLog {
|
||||
private static final String TAG = "KMLog";
|
||||
|
||||
private static final String KEYBOARD_TAG = "keyboardId";
|
||||
private static final String KEYBOARD_COUNT_TAG = "installedKeyboardCount";
|
||||
private static final String MODEL_TAG = "modelId";
|
||||
private static final String LANGCODE_TAG = "languageCode";
|
||||
|
||||
// Some of the methods used to generate debug logging information can, themselves,
|
||||
// trigger errors that can also trigger the same logging. We must not get
|
||||
// caught in an infinite loop / stack-overflow; this field helps us avoid states
|
||||
// that would otherwise cause error-looping, etc.
|
||||
private static boolean isLogging = false;
|
||||
|
||||
private static void tagDebugInfo() {
|
||||
String kbdId = "";
|
||||
String lngCode = "";
|
||||
String modelId = "";
|
||||
int kbdCount = 0;
|
||||
// Do not risk raising a new error while tagging info for another error.
|
||||
try {
|
||||
// Both take a context parameter... but don't actually need or use it!
|
||||
Keyboard kbd = KMManager.getCurrentKeyboardInfo(null);
|
||||
kbdCount = KMManager.getKeyboardsList(null).size();
|
||||
if (kbd != null) {
|
||||
kbdId = kbd.getKeyboardID();
|
||||
lngCode = kbd.getLanguageCode();
|
||||
Map<String, String> modelMap = KMManager.getAssociatedLexicalModel(kbd.getLanguageID());
|
||||
if (modelMap != null) {
|
||||
modelId = modelMap.get(KMKey_LexicalModelID);
|
||||
if (modelId == null) {
|
||||
modelId = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
String msg = ex.getMessage() == null ? "" : ex.getMessage();
|
||||
Sentry.setExtra("debugLoggingError", msg);
|
||||
}
|
||||
Sentry.setExtra(KEYBOARD_TAG, kbdId);
|
||||
Sentry.setExtra(KEYBOARD_COUNT_TAG, "" + kbdCount);
|
||||
Sentry.setExtra(LANGCODE_TAG, lngCode);
|
||||
Sentry.setExtra(MODEL_TAG, modelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to log info and send to Sentry
|
||||
* @param tag String of the caller
|
||||
* @param msg String of the info message
|
||||
*/
|
||||
public static void LogInfo(String tag, String msg) {
|
||||
if(isLogging) {
|
||||
return;
|
||||
}
|
||||
isLogging = true;
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
Log.i(tag, msg);
|
||||
|
||||
if (DependencyUtil.libraryExists(LibraryType.SENTRY) && Sentry.isEnabled()) {
|
||||
tagDebugInfo();
|
||||
Sentry.captureMessage(msg, SentryLevel.INFO);
|
||||
}
|
||||
}
|
||||
isLogging = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,9 +98,15 @@ public final class KMLog {
|
|||
return;
|
||||
}
|
||||
|
||||
if(isLogging) {
|
||||
return;
|
||||
}
|
||||
isLogging = true;
|
||||
|
||||
Log.i(tag, msg);
|
||||
|
||||
if (!DependencyUtil.libraryExists(LibraryType.SENTRY) || !Sentry.isEnabled()) {
|
||||
isLogging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +132,9 @@ public final class KMLog {
|
|||
crumb.setData("stacktrace", trace);
|
||||
}
|
||||
}
|
||||
tagDebugInfo();
|
||||
Sentry.addBreadcrumb(crumb);
|
||||
isLogging = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -83,6 +143,10 @@ public final class KMLog {
|
|||
* @param msg String of the error message
|
||||
*/
|
||||
public static void LogError(String tag, String msg) {
|
||||
if(isLogging) {
|
||||
return;
|
||||
}
|
||||
isLogging = true;
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
Log.e(tag, msg);
|
||||
|
||||
|
|
@ -91,9 +155,11 @@ public final class KMLog {
|
|||
}
|
||||
|
||||
if (DependencyUtil.libraryExists(LibraryType.SENTRY) && Sentry.isEnabled()) {
|
||||
tagDebugInfo();
|
||||
Sentry.captureMessage(msg, SentryLevel.ERROR);
|
||||
}
|
||||
}
|
||||
isLogging = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -103,6 +169,10 @@ public final class KMLog {
|
|||
* @param e Throwable exception
|
||||
*/
|
||||
public static void LogException(String tag, String msg, Throwable e) {
|
||||
if(isLogging) {
|
||||
return;
|
||||
}
|
||||
isLogging = true;
|
||||
String errorMsg = "";
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
errorMsg = msg + "\n" + e;
|
||||
|
|
@ -116,9 +186,11 @@ public final class KMLog {
|
|||
}
|
||||
|
||||
if (DependencyUtil.libraryExists(LibraryType.SENTRY) && Sentry.isEnabled()) {
|
||||
tagDebugInfo();
|
||||
Sentry.addBreadcrumb(errorMsg);
|
||||
Sentry.captureException(e);
|
||||
}
|
||||
isLogging = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -131,7 +203,12 @@ public final class KMLog {
|
|||
*/
|
||||
public static void LogExceptionWithData(String tag, String msg,
|
||||
String objName, Object obj, Throwable e) {
|
||||
if(isLogging) {
|
||||
return;
|
||||
}
|
||||
isLogging = true;
|
||||
if (obj != null && DependencyUtil.libraryExists(LibraryType.SENTRY) && Sentry.isEnabled()) {
|
||||
tagDebugInfo();
|
||||
String objStr = null;
|
||||
try {
|
||||
objStr = obj.toString();
|
||||
|
|
@ -141,6 +218,10 @@ public final class KMLog {
|
|||
}
|
||||
// Report the original exception
|
||||
LogException(tag, msg, e);
|
||||
// And remove the exception-specific tagged data, lest it also be
|
||||
// tracked on subsequent errors not associated with the current call.
|
||||
Sentry.removeExtra(objName);
|
||||
}
|
||||
isLogging = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ public final class VersionUtils {
|
|||
public static final String TAG = "VersionUtils";
|
||||
|
||||
public static boolean isLocalBuild() {
|
||||
return BuildConfig.VERSION_ENVIRONMENT.equalsIgnoreCase("local");
|
||||
return BuildConfig.KEYMAN_VERSION_ENVIRONMENT.equalsIgnoreCase("local");
|
||||
}
|
||||
|
||||
public static boolean isTestBuild() {
|
||||
return BuildConfig.VERSION_ENVIRONMENT.equalsIgnoreCase("test");
|
||||
return BuildConfig.KEYMAN_VERSION_ENVIRONMENT.equalsIgnoreCase("test");
|
||||
}
|
||||
|
||||
// Utility for local and PR test builds - e.g. force check of keyboard updates
|
||||
|
|
|
|||
|
|
@ -86,6 +86,14 @@
|
|||
<string name="fatal_keyboard_error" comment="Fatal keyboard error (keyboard ID::packageID for language). Will load default keyboard"> Fatální chyba klávesnice s %1$s:%2$s pro jazyk %3$s . Načítání výchozí klávesnice.</string>
|
||||
<!-- Context: Fatal keyboard error. -->
|
||||
<string name="fatal_keyboard_error_short" comment="Error in keyboard (keyboard ID::packageID for language)."> Chyba v klávesnici %1$s:%2$s pro jazyk %3$s.</string>
|
||||
<!-- Context: Alert Dialog body: System WebView not installed -->
|
||||
<string name="body_install_webview" comment="Notification when WebView not installed">Keyman vyžaduje, aby byl nainstalován WebView.“</string>
|
||||
<!-- Context: Alert Dialog body: System WebView installed but not enabled -->
|
||||
<string name="body_enable_webview" comment="Notification when WebView installed but not enabled">Keyman vyžaduje, aby byl povolen WebView.“</string>
|
||||
<!-- Context Button label: Install WebView -->
|
||||
<string name="label_install_webview" comment="Button label to install webview">Nainstalovat WebView</string>
|
||||
<!-- Context Button label: Enable WebView -->
|
||||
<string name="label_enable_webview" comment="Button label to enable webview">Povolit WebView</string>
|
||||
<!-- Context: Query for associated dictionary -->
|
||||
<string name="query_associated_model" comment="Check if there's an available dictionary to download">Kontroluji související slovník ke stažení</string>
|
||||
<string name="cannot_query_associated_model" comment="Cannot reach server to check if there's an available dictionary to download"> Nelze se připojit ke Keyman serveru a zkontrolovat, zda je možné stáhnout přidružený slovník</string>
|
||||
|
|
@ -119,6 +127,8 @@
|
|||
<string name="failed_to_retrieve_file" comment="Failed to retrieve downloaded file">Nepodařilo se načíst stažený soubor</string>
|
||||
<!-- Context: General Updates -->
|
||||
<string name="update_check_unavailable" comment="Error message when a Keyman server can't be reached">Přístup k serveru se nezdařil!</string>
|
||||
<!-- Context: Update-check failure notification -->
|
||||
<string name="update_check_download_manager_disabled" comment="Notification that a system service needed for updates is disabled">DownloadManager zakázán - nelze zkontrolovat aktualizace</string>
|
||||
<!-- Context: General Updates -->
|
||||
<string name="update_check_current" comment="Notification that all resources are up to date">"Všechny zdroje jsou aktuální!"</string>
|
||||
<!-- Context: General Updates -->
|
||||
|
|
|
|||
6
android/KMEA/app/src/main/res/values-hdpi/dimens.xml
Normal file
6
android/KMEA/app/src/main/res/values-hdpi/dimens.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Dimens for hdpi Portrait (Phone) -->
|
||||
<resources>
|
||||
<dimen name="banner_height">40dp</dimen>
|
||||
<dimen name="keyboard_height">170dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -80,6 +80,14 @@
|
|||
<string name="fatal_keyboard_error" comment="Fatal keyboard error (keyboard ID::packageID for language). Will load default keyboard"> មានបញ្ហាធ្ងន់ធ្ងរចំពោះក្ដារចុច %1$s:%2$s សម្រាប់ភាសា %3$s។ កំពុងផ្ទុកក្ដារចុចលំនាំដើម។</string>
|
||||
<!-- Context: Fatal keyboard error. -->
|
||||
<string name="fatal_keyboard_error_short" comment="Error in keyboard (keyboard ID::packageID for language)."> បញ្ហាក្នុងក្ដារចុច %1$s:%2$s សម្រាប់ភាសា %3$s។</string>
|
||||
<!-- Context: Alert Dialog body: System WebView not installed -->
|
||||
<string name="body_install_webview" comment="Notification when WebView not installed">Keyman តម្រូវឱ្យដំឡើង WebView ។\"</string>
|
||||
<!-- Context: Alert Dialog body: System WebView installed but not enabled -->
|
||||
<string name="body_enable_webview" comment="Notification when WebView installed but not enabled">Keyman តម្រូវឱ្យបើក WebView ។\"</string>
|
||||
<!-- Context Button label: Install WebView -->
|
||||
<string name="label_install_webview" comment="Button label to install webview">ដំឡើង WebView</string>
|
||||
<!-- Context Button label: Enable WebView -->
|
||||
<string name="label_enable_webview" comment="Button label to enable webview">បើក WebView</string>
|
||||
<!-- Context: Query for associated dictionary -->
|
||||
<string name="query_associated_model" comment="Check if there's an available dictionary to download">កំពុងពិនិត្យរកបញ្ជីពាក្យពាក់ព័ន្ធដើម្បីទាញយក</string>
|
||||
<string name="cannot_query_associated_model" comment="Cannot reach server to check if there's an available dictionary to download"> មិនអាចភ្ជាប់ទៅម៉ាស៊ីនមេ Keyman ដើម្បីរកបញ្ជីពាក្យសម្រាប់ទាញយកបានទេ</string>
|
||||
|
|
@ -113,6 +121,8 @@
|
|||
<string name="failed_to_retrieve_file" comment="Failed to retrieve downloaded file">រកមិនឃើញឯកសារដែលបានទាញយក</string>
|
||||
<!-- Context: General Updates -->
|
||||
<string name="update_check_unavailable" comment="Error message when a Keyman server can't be reached">មិនអាចចូលប្រើម៉ាស៊ីនមេបានទេ!</string>
|
||||
<!-- Context: Update-check failure notification -->
|
||||
<string name="update_check_download_manager_disabled" comment="Notification that a system service needed for updates is disabled">DownloadManager បានបិទដំណើរការ - មិនអាចពិនិត្យរកអាប់ដេតផ្សេងៗ</string>
|
||||
<!-- Context: General Updates -->
|
||||
<string name="update_check_current" comment="Notification that all resources are up to date">"ធនធានទាំងអស់គឺថ្មីបំផុតហើយ!"</string>
|
||||
<!-- Context: General Updates -->
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Dimens for hdpi Landscape (Phone) -->
|
||||
<resources>
|
||||
<dimen name="banner_height">25dp</dimen>
|
||||
<dimen name="keyboard_height">100dp</dimen>
|
||||
</resources>
|
||||
18
android/KMEA/app/src/main/res/values-land-xhdpi/dimens.xml
Normal file
18
android/KMEA/app/src/main/res/values-land-xhdpi/dimens.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Dimens for Landscape (Extra-high-density ~320dpi) -->
|
||||
<resources>
|
||||
<dimen name="banner_height">30dp</dimen>
|
||||
<dimen name="keyboard_height">140dp</dimen>
|
||||
<dimen name="key_width">83.5dp</dimen>
|
||||
<dimen name="key_height">78.5dp</dimen>
|
||||
<dimen name="popup_arrow_width">38dp</dimen>
|
||||
<dimen name="popup_arrow_height">14dp</dimen>
|
||||
<dimen name="popup_margin">6dp</dimen>
|
||||
<dimen name="popup_padding">4dp</dimen>
|
||||
<dimen name="popup_offset_y">8dp</dimen>
|
||||
<dimen name="help_bubble_width">125dp</dimen>
|
||||
<dimen name="help_bubble_height">85dp</dimen>
|
||||
<dimen name="help_bubble_offset_x">0.5dp</dimen>
|
||||
<dimen name="help_bubble_offset_y">8dp</dimen>
|
||||
<dimen name="fab_margin">6dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Dimens for Landscape (Phone) -->
|
||||
<resources>
|
||||
<dimen name="banner_height">40dp</dimen>
|
||||
<dimen name="keyboard_height">100dp</dimen>
|
||||
<dimen name="banner_height">28dp</dimen>
|
||||
<dimen name="keyboard_height">120dp</dimen>
|
||||
<dimen name="key_width">49.25dp</dimen>
|
||||
<dimen name="key_height">49.25dp</dimen>
|
||||
<dimen name="popup_arrow_width">21dp</dimen>
|
||||
|
|
|
|||
|
|
@ -80,6 +80,14 @@
|
|||
<string name="fatal_keyboard_error" comment="Fatal keyboard error (keyboard ID::packageID for language). Will load default keyboard"> ကဳဗုဒ်ယောၚ်ယာဇၞော်ဇၞော်နကဵု %1$s:%2$s သွက် ဘာသာ %3$s ။ ဂြဲပ္တိုန်မံၚ် ကဳဗုဒ်ပကတိ။</string>
|
||||
<!-- Context: Fatal keyboard error. -->
|
||||
<string name="fatal_keyboard_error_short" comment="Error in keyboard (keyboard ID::packageID for language)."> တၚ်ယောၚ်ယာ ပ္ဍဲကဳဗုဒ် %1$s:%2$s သွက် ဘာသာ %3$s</string>
|
||||
<!-- Context: Alert Dialog body: System WebView not installed -->
|
||||
<string name="body_install_webview" comment="Notification when WebView not installed">သ္ဂောံဂြဲဖျေံ Keyman ဂှ် ဒးသုၚ်စောဲ WebView ရောၚ်။</string>
|
||||
<!-- Context: Alert Dialog body: System WebView installed but not enabled -->
|
||||
<string name="body_enable_webview" comment="Notification when WebView installed but not enabled">သ္ဂောံပံက် Keyman ဂှ် ဒးသုၚ်စောဲ WebView ရောၚ်။</string>
|
||||
<!-- Context Button label: Install WebView -->
|
||||
<string name="label_install_webview" comment="Button label to install webview">ပ္တိုန်စုတ် WebView ရောၚ်</string>
|
||||
<!-- Context Button label: Enable WebView -->
|
||||
<string name="label_enable_webview" comment="Button label to enable webview">ပံက် WebView</string>
|
||||
<!-- Context: Query for associated dictionary -->
|
||||
<string name="query_associated_model" comment="Check if there's an available dictionary to download">စၟဳစၟတ်ဒၟံၚ် အဘိဓာန် မဆက်စပ် သ္ဂောံဂြဲဖျေံ</string>
|
||||
<string name="cannot_query_associated_model" comment="Cannot reach server to check if there's an available dictionary to download"> သ္ဂောံဂြဲဖျေံ အဘိဓာန်မဆက်စပ်တံဂှ် ဆက်စၠောံကု သာပါ ကဳမာန်ဟွံဂွံ</string>
|
||||
|
|
@ -113,6 +121,8 @@
|
|||
<string name="failed_to_retrieve_file" comment="Failed to retrieve downloaded file">ဝှာၚ်မဂၠောၚ်ဂြဲဖျေံလဝ်ဂှ် ကလေၚ်ကေတ်ဟွံဂွံ</string>
|
||||
<!-- Context: General Updates -->
|
||||
<string name="update_check_unavailable" comment="Error message when a Keyman server can't be reached">ဆက်စၠောံကုသာပါဟွံအံၚ်ဇၞး!</string>
|
||||
<!-- Context: Update-check failure notification -->
|
||||
<string name="update_check_download_manager_disabled" comment="Notification that a system service needed for updates is disabled">စက်ဂြဲကၟာတ်လဝ်ရောၚ် - စၟဳစၟတ်တၚ်သမၠုၚ်ဟွံဂွံ</string>
|
||||
<!-- Context: General Updates -->
|
||||
<string name="update_check_current" comment="Notification that all resources are up to date">"တံရိုဟ်ဖအိုတ်ဂှ် ဒှ်တၟိရ!"</string>
|
||||
<!-- Context: General Updates -->
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Dimens for Landscape (Tablet 7") -->
|
||||
<resources>
|
||||
<dimen name="banner_height">50dp</dimen>
|
||||
<dimen name="keyboard_height">140dp</dimen>
|
||||
<dimen name="banner_height">45dp</dimen>
|
||||
<dimen name="keyboard_height">200dp</dimen>
|
||||
<dimen name="key_width">73.5dp</dimen>
|
||||
<dimen name="key_height">58.5dp</dimen>
|
||||
<dimen name="popup_arrow_width">32dp</dimen>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<!-- Dimens for Landscape (Tablet 10") -->
|
||||
<resources>
|
||||
<dimen name="banner_height">60dp</dimen>
|
||||
<dimen name="keyboard_height">200dp</dimen>
|
||||
<dimen name="keyboard_height">280dp</dimen>
|
||||
<dimen name="key_width">98.5dp</dimen>
|
||||
<dimen name="key_height">98.5dp</dimen>
|
||||
<dimen name="popup_arrow_width">42dp</dimen>
|
||||
|
|
|
|||
6
android/KMEA/app/src/main/res/values-xhdpi/dimens.xml
Normal file
6
android/KMEA/app/src/main/res/values-xhdpi/dimens.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Dimens for xhdpi Portrait (Phone) -->
|
||||
<resources>
|
||||
<dimen name="banner_height">50dp</dimen>
|
||||
<dimen name="keyboard_height">270dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -5,10 +5,10 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'com.android.tools.build:gradle:8.9.2'
|
||||
// io.sentry:sentry-android-gradle-plugin not available for library project
|
||||
classpath 'io.sentry:sentry-android:7.8.0'
|
||||
classpath 'name.remal:gradle-plugins:1.5.0'
|
||||
classpath 'name.remal:gradle-plugins:1.9.2'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
|
||||
# ################################ Main script ################################
|
||||
|
||||
|
|
@ -28,8 +29,7 @@ builder_describe "Builds Keyman Engine for Android." \
|
|||
"configure" \
|
||||
"build" \
|
||||
"test Runs lint and unit tests." \
|
||||
":engine Builds Engine" \
|
||||
"--ci Don't start the Gradle daemon. For CI"
|
||||
":engine Builds Engine"
|
||||
|
||||
# parse before describe_outputs to check debug flags
|
||||
builder_parse "$@"
|
||||
|
|
@ -37,7 +37,7 @@ builder_parse "$@"
|
|||
if builder_is_debug_build; then
|
||||
builder_heading "### Debug config ####"
|
||||
CONFIG="debug"
|
||||
BUILD_FLAGS="assembleDebug -x lint -x test"
|
||||
BUILD_FLAGS="assembleDebug -x lintDebug -x testDebug"
|
||||
TEST_FLAGS="-x assembleDebug lintDebug testDebug"
|
||||
JUNIT_RESULTS="##teamcity[importData type='junit' path='keyman\android\KMEA\app\build\test-results\testDebugUnitTest\']"
|
||||
fi
|
||||
|
|
@ -51,7 +51,7 @@ builder_describe_outputs \
|
|||
# Parse args
|
||||
|
||||
DAEMON_FLAG=
|
||||
if builder_has_option --ci; then
|
||||
if builder_is_ci_build; then
|
||||
DAEMON_FLAG=--no-daemon
|
||||
fi
|
||||
|
||||
|
|
@ -82,8 +82,6 @@ if builder_start_action build:engine; then
|
|||
cp "$KEYMAN_WEB_ROOT/build/app/resources/osk/kmwosk.css" "$ENGINE_ASSETS/kmwosk.css"
|
||||
cp "$KEYMAN_WEB_ROOT/build/app/resources/osk/globe-hint.css" "$ENGINE_ASSETS/globe-hint.css"
|
||||
cp "$KEYMAN_WEB_ROOT/build/app/resources/osk/keymanweb-osk.ttf" "$ENGINE_ASSETS/keymanweb-osk.ttf"
|
||||
|
||||
cp "$KEYMAN_ROOT/node_modules/@sentry/browser/build/bundle.min.js" "$ENGINE_ASSETS/sentry.min.js"
|
||||
cp "$KEYMAN_ROOT/web/src/engine/sentry-manager/build/lib/index.js" "$ENGINE_ASSETS/keyman-sentry.js"
|
||||
|
||||
echo "Copying es6-shim polyfill"
|
||||
|
|
@ -98,7 +96,7 @@ fi
|
|||
|
||||
if builder_start_action test:engine; then
|
||||
|
||||
if builder_has_option --ci; then
|
||||
if builder_is_ci_build; then
|
||||
# Report JUnit test results to CI
|
||||
echo "$JUNIT_RESULTS"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#Wed Apr 30 11:17:37 ICT 2025
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -141,6 +141,10 @@ android {
|
|||
aaptOptions {
|
||||
noCompress "kmp"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
```
|
||||
5. After the `android {}` object, include the following:
|
||||
````gradle
|
||||
|
|
@ -154,7 +158,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
api (name:'keyman-engine', ext:'aar')
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
api(name: 'keyman-engine', ext: 'aar')
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'com.android.tools.build:gradle:8.9.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
|
|
@ -22,8 +23,7 @@ builder_describe "Build KMSample1 app for Android." \
|
|||
"configure" \
|
||||
"build" \
|
||||
"test" \
|
||||
":app KMSample1" \
|
||||
"--ci Don't start the Gradle daemon. Use for CI"
|
||||
":app KMSample1"
|
||||
|
||||
# parse before describe_outputs to check debug flags
|
||||
builder_parse "$@"
|
||||
|
|
@ -46,7 +46,7 @@ builder_describe_outputs \
|
|||
|
||||
# Parse args
|
||||
|
||||
if builder_has_option --ci; then
|
||||
if builder_is_ci_build; then
|
||||
SAMPLE_FLAGS="$SAMPLE_FLAGS -no-daemon"
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -18,4 +18,8 @@
|
|||
# org.gradle.parallel=true
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
# AGP 8.0 generates R classes for resources defined in the current module only.
|
||||
android.nonTransitiveRClass=false
|
||||
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
api (name:'keyman-engine', ext:'aar')
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'com.android.tools.build:gradle:8.9.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
|
|
@ -22,8 +23,7 @@ builder_describe "Build KMSample2 app for Android." \
|
|||
"configure" \
|
||||
"build" \
|
||||
"test" \
|
||||
":app KMSample2" \
|
||||
"--ci Don't start the Gradle daemon. Use for CI"
|
||||
":app KMSample2"
|
||||
|
||||
# parse before describe_outputs to check debug flags
|
||||
builder_parse "$@"
|
||||
|
|
@ -47,7 +47,7 @@ builder_describe_outputs \
|
|||
|
||||
# Parse args
|
||||
|
||||
if builder_has_option --ci; then
|
||||
if builder_is_ci_build; then
|
||||
SAMPLE_FLAGS="$SAMPLE_FLAGS -no-daemon"
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -18,4 +18,8 @@
|
|||
# org.gradle.parallel=true
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
|
||||
# AGP 8.0 generates R classes for resources defined in the current module only.
|
||||
android.nonTransitiveRClass=false
|
||||
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
|
|
|
|||
|
|
@ -14,15 +14,19 @@ android {
|
|||
noCompress "kmp"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.keyman.android.tests.keyboardHarness"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
|
||||
// VERSION_CODE and VERSION_NAME from version.gradle
|
||||
versionCode VERSION_CODE as Integer
|
||||
versionName VERSION_NAME
|
||||
buildConfigField "String", "VERSION_ENVIRONMENT", "\""+VERSION_ENVIRONMENT+"\""
|
||||
// KEYMAN_VERSION_CODE and KEYMAN_VERSION_NAME from version.gradle
|
||||
versionCode KEYMAN_VERSION_CODE as Integer
|
||||
versionName KEYMAN_VERSION_NAME
|
||||
buildConfigField "String", "KEYMAN_VERSION_ENVIRONMENT", "\""+KEYMAN_VERSION_ENVIRONMENT+"\""
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
|
@ -42,7 +46,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
api (name:'keyman-engine', ext:'aar')
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.0'
|
||||
classpath 'com.android.tools.build:gradle:8.9.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
|
|
@ -22,8 +23,7 @@ builder_describe "Build KeyboardHarness test app for Android." \
|
|||
"configure" \
|
||||
"build" \
|
||||
"test" \
|
||||
":app KeyboardHarness" \
|
||||
"--ci Don't start the Gradle daemon. Use for CI"
|
||||
":app KeyboardHarness"
|
||||
|
||||
# parse before describe outputs to check debug flags
|
||||
builder_parse "$@"
|
||||
|
|
@ -33,7 +33,7 @@ ARTIFACT="app-release-unsigned.apk"
|
|||
if builder_is_debug_build; then
|
||||
builder_heading "### Debug config ####"
|
||||
CONFIG="debug"
|
||||
BUILD_FLAGS="assembleDebug -x lint -x test"
|
||||
BUILD_FLAGS="assembleDebug -x lintDebug -x testDebug"
|
||||
TEST_FLAGS="-x assembleDebug lintDebug testDebug"
|
||||
ARTIFACT="app-$CONFIG.apk"
|
||||
fi
|
||||
|
|
@ -55,7 +55,7 @@ SHLVL=0
|
|||
# Parse args
|
||||
|
||||
# Build flags that apply to all targets
|
||||
if builder_has_option --ci; then
|
||||
if builder_is_ci_build; then
|
||||
BUILD_FLAGS="$BUILD_FLAGS -no-daemon"
|
||||
TEST_FLAGS="$TEST_FLAGS -no-daemon"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -19,3 +19,6 @@
|
|||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx1024m
|
||||
|
||||
# AGP 8.0 generates R classes for resources defined in the current module only.
|
||||
android.nonTransitiveRClass=false
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
|
||||
// VERSION_CODE and VERSION_NAME from version.gradle
|
||||
versionCode VERSION_CODE as Integer
|
||||
versionName VERSION_NAME
|
||||
buildConfigField "String", "VERSION_ENVIRONMENT", "\""+VERSION_ENVIRONMENT+"\""
|
||||
// KEYMAN_VERSION_CODE and KEYMAN_VERSION_NAME from version.gradle
|
||||
versionCode KEYMAN_VERSION_CODE as Integer
|
||||
versionName KEYMAN_VERSION_NAME
|
||||
buildConfigField "String", "KEYMAN_VERSION_ENVIRONMENT", "\""+KEYMAN_VERSION_ENVIRONMENT+"\""
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@
|
|||
#
|
||||
# Build Keyman Engine for Android, Keyman for Android, OEM FirstVoices Android app,
|
||||
# Samples: KMsample1 and KMSample2, Test - KeyboardHarness
|
||||
#
|
||||
# OEM FirstVoices Android app requires the following env vars set:
|
||||
# RELEASE_OEM should be set
|
||||
# RELEASE_OEM_FIRSTVOICES should be true
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
|
|
@ -9,9 +14,22 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-utils-ci.inc.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/zip.inc.sh"
|
||||
|
||||
################################ Main script ################################
|
||||
|
||||
#
|
||||
# Restrict available OEM publish targets to those that can be built on the current system
|
||||
#
|
||||
|
||||
oemtargets=()
|
||||
if [ ! -z "${RELEASE_OEM+x}" ]; then
|
||||
if [ "${RELEASE_OEM_FIRSTVOICES-false}" = true ]; then
|
||||
oemtargets+=(":fv=../oem/firstvoices/android OEM FirstVoices for Android app")
|
||||
fi
|
||||
fi
|
||||
|
||||
builder_describe \
|
||||
"Build Keyman Engine for Android, Keyman for Android, and FirstVoices Android app." \
|
||||
"@/resources/tools/check-markdown test:help" \
|
||||
|
|
@ -20,7 +38,8 @@ builder_describe \
|
|||
build \
|
||||
test \
|
||||
"publish Publishes symbols to Sentry and the APKs to the Play Store." \
|
||||
--ci+ \
|
||||
"archive Copy release artifacts to upload/ and rsync to downloads.keyman" \
|
||||
"--ci+ Deprecated build option. Remove in 20.0" \
|
||||
--upload-sentry+ \
|
||||
":engine=KMEA Keyman Engine for Android" \
|
||||
":app=KMAPro Keyman for Android" \
|
||||
|
|
@ -28,7 +47,7 @@ builder_describe \
|
|||
":sample1=Samples/KMSample1 Sample app: KMSample1" \
|
||||
":sample2=Samples/KMSample2 Sample app: KMSample2" \
|
||||
":keyboardharness=Tests/KeyboardHarness Test app: KeyboardHarness" \
|
||||
":fv=../oem/firstvoices/android OEM FirstVoices for Android app"
|
||||
"${oemtargets[@]}" \
|
||||
|
||||
builder_parse "$@"
|
||||
|
||||
|
|
@ -53,4 +72,51 @@ function do_test_help() {
|
|||
|
||||
builder_run_action test:help do_test_help
|
||||
|
||||
builder_run_child_actions publish
|
||||
builder_run_child_actions publish
|
||||
|
||||
# Copy release artifacts to upload/ and rsync to downloads.keyman.com
|
||||
if builder_start_action archive; then
|
||||
UPLOAD_PATH="$KEYMAN_ROOT/android/upload/${KEYMAN_VERSION}"
|
||||
KEYMAN_ENGINE_ANDROID_ZIP="keyman-engine-android-${KEYMAN_VERSION}.zip"
|
||||
KEYMAN_APK="keyman-${KEYMAN_VERSION}.apk"
|
||||
FIRSTVOICES_APK="firstvoices-${KEYMAN_VERSION}.apk"
|
||||
ZIP_FILE="${UPLOAD_PATH}/${KEYMAN_ENGINE_ANDROID_ZIP}"
|
||||
ZIP_FLAGS=("-q" "-r") # quiet, recursive
|
||||
|
||||
mkdir -p "${UPLOAD_PATH}"
|
||||
|
||||
# Create Keyman Engine for Android archive
|
||||
builder_echo "Copying Keyman Engine for Android into ${UPLOAD_PATH}..."
|
||||
cd "${UPLOAD_PATH}"
|
||||
cp "${KEYMAN_ROOT}/android/KMAPro/kMAPro/libs/keyman-engine.aar" ./
|
||||
add_zip_files "${ZIP_FILE}" "${ZIP_FLAGS[@]}" "keyman-engine.aar"
|
||||
rm -f "keyman-engine.aar"
|
||||
|
||||
builder_echo "Copying Keyman Engine for Android Sample projects into ${UPLOAD_PATH}..."
|
||||
cp -rf "${KEYMAN_ROOT}/android/Samples" ./
|
||||
add_zip_files "${ZIP_FILE}" "-x@../../zip-excludes" "${ZIP_FLAGS[@]}" "Samples"
|
||||
rm -rf "Samples"
|
||||
|
||||
# Copy release APK
|
||||
cp "${KEYMAN_ROOT}/android/KMAPro/kMAPro/build/outputs/apk/release/${KEYMAN_APK}" ./
|
||||
|
||||
# FirstVoices app
|
||||
|
||||
if [ "${RELEASE_OEM_FIRSTVOICES-false}" = true ]; then
|
||||
cp "${KEYMAN_ROOT}/oem/firstvoices/android/app/build/outputs/apk/release/${FIRSTVOICES_APK}" ./
|
||||
fi
|
||||
|
||||
#
|
||||
# Write download info files
|
||||
#
|
||||
|
||||
cd "${UPLOAD_PATH}"
|
||||
write_download_info "Keyman Engine for Android" "${KEYMAN_ENGINE_ANDROID_ZIP}" "${KEYMAN_VERSION}" "${KEYMAN_TIER}" "android"
|
||||
write_download_info "Keyman for Android" "${KEYMAN_APK}" "${KEYMAN_VERSION}" "${KEYMAN_TIER}" "android"
|
||||
|
||||
if [ "${RELEASE_OEM_FIRSTVOICES-false}" = true ]; then
|
||||
write_download_info "FirstVoices Keyboards" "${FIRSTVOICES_APK}" "${KEYMAN_VERSION}" "${KEYMAN_TIER}" "android"
|
||||
fi
|
||||
|
||||
builder_finish_action success archive
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -3,14 +3,19 @@ title: KMManager.applyKeyboardHeight()
|
|||
---
|
||||
|
||||
## Summary
|
||||
The **applyKeyboardHeight()** method sets the height of the keyboard frame for
|
||||
the device's current [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali)
|
||||
(portrait vs landscape).
|
||||
The **applyKeyboardHeight()** method sets the height of the keyboard frame for
|
||||
the device's current [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali)
|
||||
(portrait vs landscape) or a specified orientation.
|
||||
|
||||
## Syntax
|
||||
```java
|
||||
KMManager.applyKeyboardHeight(Context context, int height)
|
||||
```
|
||||
or
|
||||
|
||||
```java
|
||||
KMManager.applyKeyboardHeight(Context context, int height, int orientation)
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
|
|
@ -18,25 +23,28 @@ KMManager.applyKeyboardHeight(Context context, int height)
|
|||
: The context
|
||||
|
||||
`height`
|
||||
: The height of the keyboard frame in *density-independent pixels (dp)*
|
||||
: The height of the keyboard frame in *density-independent pixels (dp)*. Pass `KMManager.KeyboardHeight_Reset` to reset the keyboard height (for current orientation) to device-specific defaults.
|
||||
|
||||
`orientation` _(Optional)_
|
||||
: Accepts a [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali) value. This is most useful if you want to change the size of the keyboard in the other (non-current) orientation. If `orientation` is not defined, keyboard height is set for the current device orientation.
|
||||
|
||||
## Description
|
||||
Use this method when you want to increase or decrease the keyboard height for
|
||||
the device in the current screen orientation. This height is independent from
|
||||
Use this method when you want to increase or decrease the keyboard height for
|
||||
the device in the current screen orientation. This height is independent from
|
||||
the height of the suggestion banner frame.
|
||||
|
||||
For reference, here's a table of the default Keyman keyboard heights for various devices and screen orientation.
|
||||
|
||||
Device Type and Screen Orientation | Default height (dp) |
|
||||
|-----------------------------------|---------------------|
|
||||
| Default handset in portrait | 205 |
|
||||
| Default handset in landscape | 150 |
|
||||
| 7" tablet in portrait | 305 |
|
||||
| 7" tablet in landscape | 200 |
|
||||
| 10" tablet in portrait | 405 |
|
||||
| 10" tablet in landscape | 300 |
|
||||
|
||||
**Note:** This new keyboard height would be applied for all platforms, so an
|
||||
Device Type | Default height (dp)<br>Portrait | Default height (dp)<br>Landscape |
|
||||
|-------------------------------|---------------------------------|----------------------------------|
|
||||
| Default handset (160dpi) | 205 | 120 |
|
||||
| High Density handset (240dpi) | 170 | 100 |
|
||||
| Extra High Density handset (320dpi) | 270 | 140 |
|
||||
| Extra Extra Extra<br>High Density handset (640 dpi) | 270 | 140 |
|
||||
| 7" tablet | 305 | 200 |
|
||||
| 10" tablet | 405 | 280 |
|
||||
|
||||
**Note:** This new keyboard height would be applied for all platforms, so an
|
||||
adjusted keyboard height for a phone would appear too small for a tablet.
|
||||
|
||||
## Examples
|
||||
|
|
@ -50,5 +58,23 @@ The following script illustrates the use of `applyKeyboardHeight()`:
|
|||
KMManager.applyKeyboardHeight(this, newKeyboardHeight);
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```java
|
||||
import android.content.res.Configuration;
|
||||
...
|
||||
// Increase the Keyman keyboard height for landscape mode to 250dp (default Keyman value for most phones is 100dp)
|
||||
int newKeyboardHeight = 250;
|
||||
KMManager.applyKeyboardHeight(this, newKeyboardHeight, Configuration.ORIENTATION_LANDSCAPE);
|
||||
```
|
||||
|
||||
|
||||
The following script illustrates the use of `applyKeyboardHeight()` to reset keyboard height to default:
|
||||
|
||||
```java
|
||||
// Reset keyboard to default height
|
||||
KMManager.applyKeyboardHeight(this, KMManager.KeyboardHeight_Reset);
|
||||
```
|
||||
|
||||
## See also
|
||||
* [getKeyboardHeight()](getKeyboardHeight)
|
||||
|
|
|
|||
55
android/docs/engine/KMManager/getDefaultKeyboardHeight.md
Normal file
55
android/docs/engine/KMManager/getDefaultKeyboardHeight.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
title: KMManager.getDefaultKeyboardHeight()
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The **`getDefaultKeyboardHeight()`** method returns the default height of the keyboard frame for the current or specefied orientation.
|
||||
|
||||
## Syntax
|
||||
|
||||
``` javascript
|
||||
KMManager.getDefaultKeyboardHeight(Context context)
|
||||
```
|
||||
or
|
||||
``` javascript
|
||||
KMManager.getDefaultKeyboardHeight(int orientation)
|
||||
```
|
||||
|
||||
### Parameters (Choose One)
|
||||
|
||||
`context` _(Alternate)_
|
||||
: The context.
|
||||
|
||||
`orientation` _(Alternate)_
|
||||
: Accepts a [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali) value. This is most useful if you want to get the size of the keyboard in the other (non-current) orientation. If `orientation` parameter is not passed in, keyboard height is returned for the current device orientation.
|
||||
|
||||
### Returns
|
||||
|
||||
Returns the default height of the keyboard frame in *density-independent pixels (dp)*.
|
||||
|
||||
## Description
|
||||
|
||||
Use this method to get the default height of the keyboard frame.
|
||||
|
||||
## Examples
|
||||
|
||||
### Example: Using `getDefaultKeyboardHeight()`
|
||||
|
||||
The following script illustrate the use of `getDefaultKeyboardHeight()`:
|
||||
|
||||
``` javascript
|
||||
int keyboardHeight = KMManager.getDefaultKeyboardHeight(this);
|
||||
```
|
||||
or
|
||||
```java
|
||||
import android.content.res.Configuration;
|
||||
...
|
||||
// Get the current Keyman keyboard height for landscape mode.
|
||||
|
||||
int keyboardHeightLandscape = KMManager.getDefaultKeyboardHeight( Configuration.ORIENTATION_LANDSCAPE);
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [applyKeyboardHeight()](applyKeyboardHeight)
|
||||
|
|
@ -12,12 +12,19 @@ frame.
|
|||
``` javascript
|
||||
KMManager.getKeyboardHeight(Context context)
|
||||
```
|
||||
or
|
||||
``` javascript
|
||||
KMManager.getKeyboardHeight(Context context, int orientation)
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
`context`
|
||||
: The context.
|
||||
|
||||
`orientation` _(Optional)_
|
||||
: Accepts a [screen orientation](https://developer.android.com/training/multiscreen/screensizes#TaskUseOriQuali) value. This is most useful if you want to get the size of the keyboard in the other (non-current) orientation. If `orientation` parameter is not passed in, keyboard height is returned for the current device orientation.
|
||||
|
||||
### Returns
|
||||
|
||||
Returns the height of the keyboard frame in *density-independent pixels
|
||||
|
|
@ -36,7 +43,15 @@ The following script illustrate the use of `getKeyboardHeight()`:
|
|||
``` javascript
|
||||
int keyboardHeight = KMManager.getKeyboardHeight(this);
|
||||
```
|
||||
or
|
||||
```java
|
||||
import android.content.res.Configuration;
|
||||
...
|
||||
// Get the current Keyman keyboard height for landscape mode.
|
||||
|
||||
int keyboardHeightLandscape = KMManager.getKeyboardHeight(this, Configuration.ORIENTATION_LANDSCAPE);
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [applyKeyboardHeight](applyKeyboardHeight)
|
||||
- [applyKeyboardHeight()](applyKeyboardHeight)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ Use this method to specify the HTML content to display in the banner to theme yo
|
|||
|
||||
If the banner theme references assets (like .svg or .css files), ensure you've also called [copyHTMLBannerAssets()](copyHTMLBannerAssets).
|
||||
|
||||
Note: The HTML banner needs to be updated whenever the keyboard is reloaded, so call this in `SystemKeyboard.onInitializeInterface(()`.
|
||||
Note: The HTML banner needs to be updated whenever the keyboard is reloaded, so call this in `SystemKeyboard.onKeyboardShown()`.
|
||||
|
||||
## Examples
|
||||
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ title: Adjust Keyboard Height - Keyman for Android Help
|
|||
|
||||
This menu is used to adjust the height of the on-screen keyboard (OSK), which does not include the suggestion banner.
|
||||
|
||||
Drag the blank OSK at the bottom of the screen to increase or decrease the keyboard height for the device's current orientation (portrait vs landscape). The adjusted keyboard heights are automatically saved when the blank OSK is released.
|
||||
Drag the blank OSK at the bottom of the screen to increase or decrease the keyboard height for the device's current orientation (portrait vs landscape). Turn the device 90 degrees to the alternate orientation and repeat the process. The adjusted keyboard heights are automatically saved when the blank OSK is released.
|
||||
|
||||

|
||||
|
||||
### Reset to Default Height
|
||||
Press the button to reset the OSK height to the default values.
|
||||
Press the button to reset the OSK height (for the current orientation) to the default device-specific height.
|
||||
|
||||

|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
//
|
||||
|
||||
def getVersionCode = { ->
|
||||
String env_version_major = System.getenv("VERSION_MAJOR")
|
||||
String env_version_minor = System.getenv("VERSION_MINOR")
|
||||
String env_version_patch = System.getenv("VERSION_PATCH")
|
||||
String env_version_major = System.getenv("KEYMAN_VERSION_MAJOR")
|
||||
String env_version_minor = System.getenv("KEYMAN_VERSION_MINOR")
|
||||
String env_version_patch = System.getenv("KEYMAN_VERSION_PATCH")
|
||||
if(env_version_patch != null && env_version_minor != null && env_version_patch != null) {
|
||||
// Version code is, for 17.1.33: 1810033. This supports up to 9999
|
||||
// builds for a given major.minor version. We only support up to 9 minor
|
||||
|
|
@ -36,10 +36,10 @@ def getVersionCode = { ->
|
|||
}
|
||||
|
||||
def getVersionMD = { ->
|
||||
String env_version = System.getenv("VERSION")
|
||||
String env_version = System.getenv("KEYMAN_VERSION")
|
||||
if (env_version != null) {
|
||||
// If building from script, we have build number in VERSION
|
||||
println "Using build $env_version from VERSION"
|
||||
// If building from script, we have build number in KEYMAN_VERSION
|
||||
println "Using build $env_version from KEYMAN_VERSION"
|
||||
return "$env_version"
|
||||
} else {
|
||||
String version_md = file("$rootPath/../VERSION.md").text.trim()
|
||||
|
|
@ -48,15 +48,15 @@ def getVersionMD = { ->
|
|||
}
|
||||
|
||||
def getVersionName = { ->
|
||||
String env_version = System.getenv("VERSION_WITH_TAG")
|
||||
String env_version = System.getenv("KEYMAN_VERSION_WITH_TAG")
|
||||
if (env_version != null) {
|
||||
// If building from script, we have build number in VERSION_WITH_TAG
|
||||
println "Using build $env_version from VERSION_WITH_TAG"
|
||||
// If building from script, we have build number in KEYMAN_VERSION_WITH_TAG
|
||||
println "Using build $env_version from KEYMAN_VERSION_WITH_TAG"
|
||||
return "$env_version"
|
||||
} else {
|
||||
// Building probably from IDE, so let's use VERSION.md and TIER.md directly
|
||||
// This is a close match with VERSION_WITH_TAG, except that 'stable' tier
|
||||
// is not normally included with VERSION_WITH_TAG
|
||||
// This is a close match with KEYMAN_VERSION_WITH_TAG, except that 'stable' tier
|
||||
// is not normally included with KEYMAN_VERSION_WITH_TAG
|
||||
String version_md = file("$rootPath/../VERSION.md").text.trim()
|
||||
String tier_md = file("$rootPath/../TIER.md").text.trim()
|
||||
println "Using build $version_md-$tier_md-local from project VERSION.md/TIER.md"
|
||||
|
|
@ -65,10 +65,10 @@ def getVersionName = { ->
|
|||
}
|
||||
|
||||
def getVersionEnvironment = { ->
|
||||
String env_environment = System.getenv("VERSION_ENVIRONMENT")
|
||||
String env_environment = System.getenv("KEYMAN_VERSION_ENVIRONMENT")
|
||||
if (env_environment != null) {
|
||||
// If building from script, we have build number in VERSION_ENVIRONMENT
|
||||
println "Using $env_environment from VERSION_ENVIRONMENT"
|
||||
// If building from script, we have build number in KEYMAN_VERSION_ENVIRONMENT
|
||||
println "Using $env_environment from KEYMAN_VERSION_ENVIRONMENT"
|
||||
return "$env_environment"
|
||||
} else {
|
||||
// Building probably from IDE, so use "local"
|
||||
|
|
@ -78,23 +78,23 @@ def getVersionEnvironment = { ->
|
|||
}
|
||||
|
||||
def getVersionGitTag = { ->
|
||||
String env_git_tag = System.getenv("VERSION_GIT_TAG")
|
||||
String env_git_tag = System.getenv("KEYMAN_VERSION_GIT_TAG")
|
||||
if (env_git_tag != null) {
|
||||
println "Using $env_git_tag from VERSION_GIT_TAG"
|
||||
println "Using $env_git_tag from KEYMAN_VERSION_GIT_TAG"
|
||||
return "$env_git_tag"
|
||||
} else {
|
||||
// Building probably from IDE
|
||||
println "Using release@$VERSION_NAME"
|
||||
return "release@$VERSION_NAME"
|
||||
println "Using release@$KEYMAN_VERSION_NAME"
|
||||
return "release@$KEYMAN_VERSION_NAME"
|
||||
}
|
||||
}
|
||||
ext {
|
||||
VERSION_CODE=getVersionCode()
|
||||
VERSION_MD=getVersionMD()
|
||||
VERSION_NAME=getVersionName()
|
||||
VERSION_ENVIRONMENT=getVersionEnvironment()
|
||||
VERSION_TAG=System.getenv("VERSION_TAG")
|
||||
VERSION_GIT_TAG=getVersionGitTag()
|
||||
KEYMAN_VERSION_CODE=getVersionCode()
|
||||
KEYMAN_VERSION_MD=getVersionMD()
|
||||
KEYMAN_VERSION_NAME=getVersionName()
|
||||
KEYMAN_VERSION_ENVIRONMENT=getVersionEnvironment()
|
||||
KEYMAN_VERSION_TAG=System.getenv("KEYMAN_VERSION_TAG")
|
||||
KEYMAN_VERSION_GIT_TAG=getVersionGitTag()
|
||||
}
|
||||
|
||||
//println "version.gradle: VERSION_TAG: " + VERSION_TAG
|
||||
//println "version.gradle: KEYMAN_VERSION_TAG: " + KEYMAN_VERSION_TAG
|
||||
1
android/zip-excludes
Normal file
1
android/zip-excludes
Normal file
|
|
@ -0,0 +1 @@
|
|||
Samples/*/build.sh
|
||||
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
Master version: https://github.com/keymanapp/api.keyman.com/blob/master/schemas/kps/17.0/kps.xsd
|
||||
|
||||
## 2025-04-02 18.0
|
||||
* Version 18.0 deprecates the following fields, and kmc-package does not use them (#13600):
|
||||
- Keyboards/Keyboard/Version
|
||||
- Keyboards/Keyboard/Name
|
||||
- Keyboards/Keyboard/RTL
|
||||
- LexicalModels/LexicalModel/Name
|
||||
- LexicalModels/LexicalModel/RTL (Note: was never read or written by any Keyman tooling)
|
||||
|
||||
## 2023-10-19 17.0
|
||||
* Version 17.0 adds:
|
||||
- LicenseFile - a .md file, usually named LICENSE.md
|
||||
|
|
@ -9,13 +17,13 @@ Master version: https://github.com/keymanapp/api.keyman.com/blob/master/schemas/
|
|||
- Info/Description - a short Markdown description of the content of the package, e.g. shown in search results on keyman.com
|
||||
- RelatedPackages - a list of other packages which relate to this one, or are deprecated by it
|
||||
- Keyboards/Keyboard/Examples - a list of typing examples for the keyboard
|
||||
- Keyboarsd/Keyboard/WebOSKFonts - a list of font filenames (not necessarily in package) suitable for rendering the on screen keyboard
|
||||
- Keyboarsd/Keyboard/WebDisplayFonts - a list of font filenames (not necessarily in package) suitable for use with the keyboard
|
||||
- Keyboards/Keyboard/WebOSKFonts - a list of font filenames (not necessarily in package) suitable for rendering the on screen keyboard
|
||||
- Keyboards/Keyboard/WebDisplayFonts - a list of font filenames (not necessarily in package) suitable for use with the keyboard
|
||||
* Version 17.0 removes:
|
||||
- LexicalModels/LexicalModel/Version - version information is not stored in the models, but only in the package metadata (was unused)
|
||||
|
||||
## 2023-04-21 7.0.1
|
||||
* Removes LexicalModel.Version, as it was never read or written
|
||||
* Removes LexicalModels/LexicalModel/Version, as it was never read or written
|
||||
|
||||
## 2021-07-19 7.0
|
||||
* Initial version 7.0
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
.kps file schema, version 7.0
|
||||
.kps file schema, version 18.0
|
||||
|
||||
Copyright (C) SIL International
|
||||
|
||||
Supports KPS files for Keyman Developer 7+
|
||||
|
||||
Expects FileVersion 7.0
|
||||
Expects FileVersion '7.0' or '12.0'
|
||||
-->
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
|
|
@ -119,10 +119,10 @@
|
|||
<xs:element minOccurs="0" maxOccurs="unbounded" name="Keyboard">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" /> <!-- deprecated: 18.0 -->
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ID" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Version" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="RTL" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Version" type="xs:string" /> <!-- deprecated: 18.0 -->
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="RTL" type="xs:string" /> <!-- deprecated: 18.0 -->
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="OSKFont" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="DisplayFont" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Languages" type="km-keyboard-languages" />
|
||||
|
|
@ -143,9 +143,9 @@
|
|||
<xs:element minOccurs="0" maxOccurs="unbounded" name="LexicalModel">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" /> <!-- deprecated: 18.0 -->
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ID" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="RTL" type="xs:string" />
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="RTL" type="xs:string" /> <!-- deprecated: 18.0 -->
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Languages" type="km-keyboard-languages" />
|
||||
</xs:all>
|
||||
</xs:complexType>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
|||
. "${THIS_SCRIPT%/*}/../../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/build/zip.inc.sh"
|
||||
|
||||
targets=()
|
||||
# Build list of available targets from subfolders, if none specified
|
||||
for d in */; do
|
||||
|
|
@ -29,7 +31,7 @@ builder_parse "$@"
|
|||
function zipsource() {
|
||||
local target="$1"
|
||||
pushd "$1" > /dev/null
|
||||
7z a -r -x!build -x"!$target.kpj.user" "${target}_source.zip" .
|
||||
add_zip_files "${target}_source.zip" -x@../zip-excludes -q -r . # -q quiet, -r recursive
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
|
|
@ -40,10 +42,10 @@ function build_index() {
|
|||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Test Keyboards - $VERSION_WITH_TAG</title>
|
||||
<title>Test Keyboards - $KEYMAN_VERSION_WITH_TAG</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test Keyboards - $VERSION_WITH_TAG</h1>
|
||||
<h1>Test Keyboards - $KEYMAN_VERSION_WITH_TAG</h1>
|
||||
<ul>
|
||||
EOF
|
||||
|
||||
|
|
@ -90,4 +92,4 @@ function build() {
|
|||
fi
|
||||
}
|
||||
|
||||
builder_run_action build build
|
||||
builder_run_action build build
|
||||
|
|
|
|||
3
common/test/keyboards/zip-excludes
Normal file
3
common/test/keyboards/zip-excludes
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
*.kpj.user
|
||||
*_source.zip
|
||||
|
|
@ -13,17 +13,9 @@ import vm from 'vm';
|
|||
// Ensure that we can successfully load the module & apply kmwLength, as it's
|
||||
// needed for some of the unit tests.
|
||||
|
||||
// // Verify that the KMW string extensions are loaded via side-effect.
|
||||
|
||||
import { extendString } from '@keymanapp/web-utils';
|
||||
|
||||
import { createRequire } from "module";
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// Ensure that our KMW string-extensions activate.
|
||||
extendString();
|
||||
assert.ok('💩'.kmwLength);
|
||||
|
||||
/**
|
||||
* Creates a MessageEvent (for inter-worker communication), with the given data payload.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
"description": "Common test resources for Keyman's JS & TS-based components & products",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"@keymanapp/resources-gosh": "*",
|
||||
"typescript": "^5.4.5"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import * as rd from 'readline';
|
||||
import * as fs from 'node:fs';
|
||||
import * as rd from 'node:readline';
|
||||
|
||||
export default async function hextobin(inputFilename: string, outputFilename?: string, options?: {silent?: boolean}): Promise<Uint8Array> {
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
"homepage": "https://github.com/keymanapp/keyman#readme",
|
||||
"devDependencies": {
|
||||
"@keymanapp/resources-gosh": "*",
|
||||
"mocha": "^10.0.0",
|
||||
"mocha-teamcity-reporter": "^4.0.0",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import convertSourceMap from 'convert-source-map'; // Transforms sourcemaps among various common formats.
|
||||
// Base64, stringified-JSON, end-of-file comment...
|
||||
|
||||
|
|
|
|||
|
|
@ -33,16 +33,16 @@ function do_build() {
|
|||
// Note: does not use the 'default' keyword so that the export name is
|
||||
// correct when converted to a CommonJS module with \`esbuild\`.
|
||||
export class KEYMAN_VERSION {
|
||||
static readonly VERSION = \"$VERSION\";
|
||||
static readonly VERSION_RELEASE =\"$VERSION_RELEASE\";
|
||||
static readonly VERSION_MAJOR = \"$VERSION_MAJOR\";
|
||||
static readonly VERSION_MINOR = \"$VERSION_MINOR\";
|
||||
static readonly VERSION_PATCH = \"$VERSION_PATCH\";
|
||||
static readonly TIER =\"$TIER\";
|
||||
static readonly VERSION_TAG = \"$VERSION_TAG\";
|
||||
static readonly VERSION_WITH_TAG = \"$VERSION_WITH_TAG\";
|
||||
static readonly VERSION_ENVIRONMENT = \"$VERSION_ENVIRONMENT\";
|
||||
static readonly VERSION_GIT_TAG = \"$VERSION_GIT_TAG\";
|
||||
static readonly VERSION = \"$KEYMAN_VERSION\";
|
||||
static readonly VERSION_RELEASE =\"$KEYMAN_VERSION_RELEASE\";
|
||||
static readonly VERSION_MAJOR = \"$KEYMAN_VERSION_MAJOR\";
|
||||
static readonly VERSION_MINOR = \"$KEYMAN_VERSION_MINOR\";
|
||||
static readonly VERSION_PATCH = \"$KEYMAN_VERSION_PATCH\";
|
||||
static readonly TIER =\"$KEYMAN_TIER\";
|
||||
static readonly VERSION_TAG = \"$KEYMAN_VERSION_TAG\";
|
||||
static readonly VERSION_WITH_TAG = \"$KEYMAN_VERSION_WITH_TAG\";
|
||||
static readonly VERSION_ENVIRONMENT = \"$KEYMAN_VERSION_ENVIRONMENT\";
|
||||
static readonly VERSION_GIT_TAG = \"$KEYMAN_VERSION_GIT_TAG\";
|
||||
}
|
||||
|
||||
// Also provides it as a 'default' export.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
"/build/"
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4.5"
|
||||
|
|
|
|||
|
|
@ -16,8 +16,5 @@ module.exports = {
|
|||
files: "src/**/*.ts",
|
||||
extends: ["../../../common/tools/eslint/eslintNoNodeImports.js"],
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
"prefer-const": "off", // TODO: enable this once infrastructure is in place and cleanup the problem cases
|
||||
},
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ function do_configure() {
|
|||
function do_test() {
|
||||
local MOCHA_FLAGS=
|
||||
|
||||
if [[ "${TEAMCITY_GIT_PATH:-}" != "" ]]; then
|
||||
if builder_is_running_on_teamcity; then
|
||||
# we're running in TeamCity
|
||||
MOCHA_FLAGS="-reporter mocha-teamcity-reporter"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
"c8": "^7.12.0",
|
||||
"chalk": "^2.4.2",
|
||||
"hexy": "^0.3.4",
|
||||
"mocha": "^8.4.0",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"mocha": {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const
|
|||
|
||||
|
||||
export function keymanTargetsFromString(targets: string, options?: {expandTargets?: boolean}): KeymanTarget[] {
|
||||
let result = new Set<KeymanTarget>(<KeymanTarget[]>targets.split(/ +/));
|
||||
const result = new Set<KeymanTarget>(<KeymanTarget[]>targets.split(/ +/));
|
||||
if(options?.expandTargets) {
|
||||
if(result.has(KeymanTarget.any)) {
|
||||
return AllKeymanTargets;
|
||||
|
|
|
|||
|
|
@ -60,14 +60,13 @@ export class KmxFileReader {
|
|||
}
|
||||
|
||||
public read(source: Uint8Array): KEYBOARD {
|
||||
let binaryKeyboard: BUILDER_COMP_KEYBOARD;
|
||||
let kmx = new KMXFile();
|
||||
binaryKeyboard = kmx.COMP_KEYBOARD.fromBuffer(source);
|
||||
const kmx = new KMXFile();
|
||||
const binaryKeyboard = kmx.COMP_KEYBOARD.fromBuffer(source);
|
||||
if(binaryKeyboard.dwIdentifier != KMXFile.FILEID_COMPILED) {
|
||||
throw new KmxFileReaderError(`Not a .kmx file: header does not contain FILEID_COMPILED`);
|
||||
}
|
||||
|
||||
let result = new KEYBOARD();
|
||||
const result = new KEYBOARD();
|
||||
result.fileVersion = binaryKeyboard.dwFileVersion;
|
||||
result.flags = binaryKeyboard.dwFlags;
|
||||
result.hotkey = binaryKeyboard.dwHotKey;
|
||||
|
|
@ -88,7 +87,7 @@ export class KmxFileReader {
|
|||
this.readGroupsAndRules(binaryKeyboard, kmx, source, result);
|
||||
|
||||
// Process system stores once we have all stores and groups loaded
|
||||
for(let store of result.stores) {
|
||||
for(const store of result.stores) {
|
||||
this.processSystemStore(store, result);
|
||||
}
|
||||
|
||||
|
|
@ -109,8 +108,8 @@ export class KmxFileReader {
|
|||
let offset = binaryKeyboard.dpGroupArray;
|
||||
for (let i = 0; i < binaryKeyboard.cxGroupArray; i++) {
|
||||
const data = new Uint8Array(source.buffer, source.byteOffset + offset);
|
||||
let binaryGroup = kmx.COMP_GROUP.fromBuffer(data);
|
||||
let group = new GROUP();
|
||||
const binaryGroup = kmx.COMP_GROUP.fromBuffer(data);
|
||||
const group = new GROUP();
|
||||
group.dpMatch = this.readString(source, binaryGroup.dpMatch);
|
||||
group.dpName = this.readString(source, binaryGroup.dpName);
|
||||
group.dpNoMatch = this.readString(source, binaryGroup.dpNoMatch);
|
||||
|
|
@ -120,8 +119,8 @@ export class KmxFileReader {
|
|||
let keyOffset = binaryGroup.dpKeyArray;
|
||||
for (let j = 0; j < binaryGroup.cxKeyArray; j++) {
|
||||
const keyData = new Uint8Array(source.buffer, source.byteOffset + keyOffset);
|
||||
let binaryKey = kmx.COMP_KEY.fromBuffer(keyData);
|
||||
let key = new KEY();
|
||||
const binaryKey = kmx.COMP_KEY.fromBuffer(keyData);
|
||||
const key = new KEY();
|
||||
key.Key = binaryKey.Key;
|
||||
key.Line = binaryKey.Line;
|
||||
key.ShiftFlags = binaryKey.ShiftFlags;
|
||||
|
|
@ -140,8 +139,8 @@ export class KmxFileReader {
|
|||
let offset = binaryKeyboard.dpStoreArray;
|
||||
for (let i = 0; i < binaryKeyboard.cxStoreArray; i++) {
|
||||
const data = new Uint8Array(source.buffer, source.byteOffset + offset);
|
||||
let binaryStore = kmx.COMP_STORE.fromBuffer(data);
|
||||
let store = new STORE();
|
||||
const binaryStore = kmx.COMP_STORE.fromBuffer(data);
|
||||
const store = new STORE();
|
||||
store.dwSystemID = binaryStore.dwSystemID;
|
||||
store.dpName = this.readString(source, binaryStore.dpName);
|
||||
store.dpString = this.readString(source, binaryStore.dpString);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { constants } from '@keymanapp/ldml-keyboard-constants';
|
||||
import { DependencySections, StrsItem, UsetItem } from './kmx-plus.js';
|
||||
import { DependencySections, StrsItem, StrsOptions, UsetItem } from './kmx-plus.js';
|
||||
import { ElementParser, ElementSegment, ElementType } from '../../ldml-keyboard/pattern-parser.js';
|
||||
import * as util from '../../util/util.js';
|
||||
import MATCH_HEX_ESCAPE = util.MATCH_HEX_ESCAPE;
|
||||
|
|
@ -33,7 +33,7 @@ export class ElementString extends Array<ElemElement> {
|
|||
* @param source if a string array, does not get reinterpreted as UnicodeSet. This is used with vars, etc. Or pass `["str"]` for an explicit 1-element elem.
|
||||
* If it is a string, will be interpreted per reorder element rules.
|
||||
*/
|
||||
static fromStrings(sections: DependencySections, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string) : ElementString {
|
||||
static fromStrings(sections: DependencySections, options: StrsOptions, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string) : ElementString {
|
||||
// the returned array
|
||||
const array = new ElementString();
|
||||
if(!source) {
|
||||
|
|
@ -69,7 +69,7 @@ export class ElementString extends Array<ElemElement> {
|
|||
}
|
||||
|
||||
for(let i = 0; i < items.length; i++) {
|
||||
let elem = new ElemElement();
|
||||
const elem = new ElemElement();
|
||||
const item = items[i];
|
||||
let typeFlag = 0;
|
||||
if (item.type === ElementType.uset) {
|
||||
|
|
@ -81,21 +81,21 @@ export class ElementString extends Array<ElemElement> {
|
|||
// error. So we can just exit here.
|
||||
return null; // UnicodeSet error
|
||||
}
|
||||
const uset = sections.usetparser.parseUnicodeSet(item.segment, needRanges);
|
||||
const uset = sections.usetparser.parseUnicodeSet(item.segment, needRanges, options?.x);
|
||||
if (!uset) {
|
||||
return null; // UnicodeSet error already thrown
|
||||
return null; // UnicodeSet error already added to callback
|
||||
}
|
||||
elem.uset = sections.uset.allocUset(uset, sections);
|
||||
elem.value = sections.strs.allocString('', {singleOk: true}); // no string
|
||||
elem.uset = sections.uset.allocUset(uset, sections, options?.x);
|
||||
elem.value = sections.strs.allocString('', {...options, singleOk: true}); // no string
|
||||
} else if (item.type === ElementType.codepoint || item.type === ElementType.escaped || item.type === ElementType.string) {
|
||||
// some kind of a string
|
||||
let str = item.segment;
|
||||
if (item.type === ElementType.escaped && !MATCH_HEX_ESCAPE.test(str)) {
|
||||
str = unescapeOneQuadString(str);
|
||||
// TODO-LDML: any other escape forms here?
|
||||
elem.value = sections.strs.allocString(str, { singleOk: true });
|
||||
elem.value = sections.strs.allocString(str, { ...options, singleOk: true });
|
||||
} else {
|
||||
elem.value = sections.strs.allocString(str, { unescape: true, singleOk: true });
|
||||
elem.value = sections.strs.allocString(str, { ...options, unescape: true, singleOk: true });
|
||||
}
|
||||
// Now did we end up with one char or no?
|
||||
if (elem.value.isOneChar) {
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@ export class Elem extends Section {
|
|||
strings: ElementString[] = [];
|
||||
constructor(sections: DependencySections) {
|
||||
super();
|
||||
this.strings.push(ElementString.fromStrings(sections, '')); // C7043: null element string
|
||||
this.strings.push(ElementString.fromStrings(sections, {}, '')); // C7043: null element string
|
||||
}
|
||||
/**
|
||||
* @param source if a string array, does not get reinterpreted as UnicodeSet. This is used with vars, etc. Or pass `["str"]` for an explicit 1-element elem.
|
||||
* If it is a string, will be interpreted per reorder element ruls.
|
||||
*/
|
||||
allocElementString(sections: DependencySections, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string): ElementString {
|
||||
let s = ElementString.fromStrings(sections, source, order, tertiary, tertiary_base, prebase);
|
||||
allocElementString(sections: DependencySections, options: StrsOptions, source: string | string[], order?: string, tertiary?: string, tertiary_base?: string, prebase?: string): ElementString {
|
||||
const s = ElementString.fromStrings(sections, options, source, order, tertiary, tertiary_base, prebase);
|
||||
if (!s) return s;
|
||||
let result = this.strings.find(item => item.isEqual(s));
|
||||
if(result === undefined) {
|
||||
|
|
@ -135,6 +135,18 @@ export class StrsItem {
|
|||
isEqual(a: StrsItem): boolean {
|
||||
return a.value === this.value && a.char === this.char;
|
||||
}
|
||||
|
||||
private _context: any = undefined;
|
||||
|
||||
/** add any context from the options to this strsitem */
|
||||
setContext(opts?: StrsOptions) {
|
||||
// At present, there's only a single piece of context available
|
||||
this._context = this._context || opts?.x;
|
||||
}
|
||||
|
||||
get context() : any {
|
||||
return this._context;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -161,6 +173,8 @@ export interface StrsOptions {
|
|||
nfd?: boolean;
|
||||
/** string can be stored as a single CharStrsItem, not in strs table. */
|
||||
singleOk?: boolean;
|
||||
/** optional context */
|
||||
x?: any;
|
||||
};
|
||||
|
||||
export class Strs extends Section {
|
||||
|
|
@ -192,6 +206,8 @@ export class Strs extends Section {
|
|||
result = new StrsItem(s);
|
||||
this.strings.push(result);
|
||||
}
|
||||
// give an option to set the context
|
||||
result.setContext(opts);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -200,7 +216,7 @@ export class Strs extends Section {
|
|||
s = s ?? '';
|
||||
// type check everything else
|
||||
if (typeof s !== 'string') {
|
||||
throw new Error('alloc_string: s must be a string, undefined, or null.');
|
||||
throw new Error(`Internal Error: processString: s must be a string, undefined, or null, not ${typeof s} ${s}`);
|
||||
}
|
||||
// substitute variables
|
||||
if (opts?.stringVariables) {
|
||||
|
|
@ -358,11 +374,13 @@ export class Vars extends Section {
|
|||
export class VarsItem extends Section {
|
||||
id: StrsItem;
|
||||
value: StrsItem;
|
||||
x?: any;
|
||||
|
||||
constructor(id: string, value: string, sections: DependencySections) {
|
||||
constructor(id: string, value: string, sections: DependencySections, x?: any) {
|
||||
super();
|
||||
this.id = sections.strs.allocString(id);
|
||||
this.value = sections.strs.allocString(value, {unescape: true});
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
valid() : boolean {
|
||||
|
|
@ -371,8 +389,8 @@ export class VarsItem extends Section {
|
|||
};
|
||||
|
||||
export class UnicodeSetItem extends VarsItem {
|
||||
constructor(id: string, value: string, sections: DependencySections, usetparser: UnicodeSetParser) {
|
||||
super(id, value, sections);
|
||||
constructor(id: string, value: string, sections: DependencySections, usetparser: UnicodeSetParser, x?: any) {
|
||||
super(id, value, sections, x);
|
||||
const needRanges = sections.usetparser.sizeUnicodeSet(value);
|
||||
if (needRanges >= 0) {
|
||||
this.unicodeSet = sections.usetparser.parseUnicodeSet(value, needRanges);
|
||||
|
|
@ -385,9 +403,9 @@ export class UnicodeSetItem extends VarsItem {
|
|||
};
|
||||
|
||||
export class SetVarItem extends VarsItem {
|
||||
constructor(id: string, value: string[], sections: DependencySections) {
|
||||
super(id, value.join(' '), sections);
|
||||
this.items = sections.elem.allocElementString(sections, value);
|
||||
constructor(id: string, value: string[], sections: DependencySections, x?: any) {
|
||||
super(id, value.join(' '), sections, x);
|
||||
this.items = sections.elem.allocElementString(sections, {x}, value);
|
||||
}
|
||||
items: ElementString; // element string array
|
||||
valid() : boolean {
|
||||
|
|
@ -396,8 +414,8 @@ export class SetVarItem extends VarsItem {
|
|||
};
|
||||
|
||||
export class StringVarItem extends VarsItem {
|
||||
constructor(id: string, value: string, sections: DependencySections) {
|
||||
super(id, value, sections);
|
||||
constructor(id: string, value: string, sections: DependencySections, x?: any) {
|
||||
super(id, value, sections, x);
|
||||
}
|
||||
// no added fields
|
||||
};
|
||||
|
|
@ -435,7 +453,7 @@ export class Tran extends Section {
|
|||
};
|
||||
|
||||
export class UsetItem {
|
||||
constructor(public uset: UnicodeSet, public str: StrsItem) {
|
||||
constructor(public uset: UnicodeSet, public str: StrsItem, public x?: any) {
|
||||
}
|
||||
compareTo(other: UsetItem) : number {
|
||||
return this.str.compareTo(other.str);
|
||||
|
|
@ -444,11 +462,11 @@ export class UsetItem {
|
|||
|
||||
export class Uset extends Section {
|
||||
usets: UsetItem[] = [];
|
||||
allocUset(set: UnicodeSet, sections: DependencySections) : UsetItem {
|
||||
allocUset(set: UnicodeSet, sections: DependencySections, x?: any) : UsetItem {
|
||||
// match the same pattern
|
||||
let result = this.usets.find(s => set.pattern == s.uset.pattern);
|
||||
if (result === undefined) {
|
||||
result = new UsetItem(set, sections.strs.allocString(set.pattern));
|
||||
result = new UsetItem(set, sections.strs.allocString(set.pattern), x);
|
||||
this.usets.push(result);
|
||||
}
|
||||
return result;
|
||||
|
|
@ -546,7 +564,7 @@ export class Keys extends Section {
|
|||
kmap: KeysKmap[] = [];
|
||||
constructor(strs: Strs) {
|
||||
super();
|
||||
let nullFlicks = new KeysFlicks(strs.allocString(''));
|
||||
const nullFlicks = new KeysFlicks(strs.allocString(''));
|
||||
this.flicks.push(nullFlicks); // C7043: null element string
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
import KVKFile, { BUILDER_KVK_FILE, BUILDER_KVK_HEADER_IDENTIFIER, BUILDER_KVK_HEADER_VERSION } from "./kvk-file.js";
|
||||
import KVKFile, { BUILDER_KVK_HEADER_IDENTIFIER, BUILDER_KVK_HEADER_VERSION } from "./kvk-file.js";
|
||||
import { VisualKeyboard, VisualKeyboardKey } from "./visual-keyboard.js";
|
||||
|
||||
export default class KvkFileReader {
|
||||
public read(source: Uint8Array): VisualKeyboard {
|
||||
let binary: BUILDER_KVK_FILE;
|
||||
let kvk = new KVKFile();
|
||||
binary = kvk.KVK_FILE.fromBuffer(source);
|
||||
const kvk = new KVKFile();
|
||||
const binary = kvk.KVK_FILE.fromBuffer(source);
|
||||
if(binary.header.identifier != BUILDER_KVK_HEADER_IDENTIFIER ||
|
||||
binary.header.version != BUILDER_KVK_HEADER_VERSION) {
|
||||
return null;
|
||||
}
|
||||
let result = new VisualKeyboard();
|
||||
const result = new VisualKeyboard();
|
||||
result.header.version = binary.header.version;
|
||||
result.header.flags = binary.header.flags;
|
||||
result.header.associatedKeyboard = binary.header.associatedKeyboard.str;
|
||||
|
|
@ -18,8 +17,8 @@ export default class KvkFileReader {
|
|||
result.header.ansiFont.size = binary.header.ansiFont.size;
|
||||
result.header.unicodeFont.name = binary.header.unicodeFont.name.str;
|
||||
result.header.unicodeFont.size = binary.header.unicodeFont.size;
|
||||
for(let binaryKey of binary.keys) {
|
||||
let key: VisualKeyboardKey = {
|
||||
for(const binaryKey of binary.keys) {
|
||||
const key: VisualKeyboardKey = {
|
||||
flags: binaryKey.flags,
|
||||
vkey: binaryKey.vkey,
|
||||
shift: binaryKey.shift,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export default class KvkFileWriter {
|
|||
this.setString(binary.header.ansiFont.name, source.header.ansiFont.name);
|
||||
this.setString(binary.header.unicodeFont.name, source.header.unicodeFont.name);
|
||||
|
||||
for(let sourceKey of source.keys) {
|
||||
for(const sourceKey of source.keys) {
|
||||
const binaryKey: BUILDER_KVK_KEY = {
|
||||
flags: sourceKey.flags,
|
||||
vkey: sourceKey.vkey,
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ export class MarkerParser {
|
|||
}
|
||||
}
|
||||
// Then, take each codepoint (from back to front)
|
||||
for (let p of [...s].reverse()) {
|
||||
for (const p of [...s].reverse()) {
|
||||
// reverse order code units, prepend to out
|
||||
out = p + out;
|
||||
|
||||
|
|
@ -525,7 +525,7 @@ export class ElementParser {
|
|||
throw Error(`Unsupported: nested square brackets in element segment: ${str}`);
|
||||
}
|
||||
const list: ElementSegment[] = [];
|
||||
for(let m of str.match(ElementParser.MATCH_ELEMENT_SEGMENTS)) {
|
||||
for(const m of str.match(ElementParser.MATCH_ELEMENT_SEGMENTS)) {
|
||||
const e = new ElementSegment(m);
|
||||
if (e.type === ElementType.escaped) {
|
||||
// unescape
|
||||
|
|
@ -534,7 +534,7 @@ export class ElementParser {
|
|||
list.push(e);
|
||||
} else {
|
||||
// need to split the escaped segment, \u{41 42} -> \u{41}, \u{42}
|
||||
for (let s of unescaped) {
|
||||
for (const s of unescaped) {
|
||||
list.push(new ElementSegment(`\\u{${s.codePointAt(0).toString(16)}}`));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export class ListItem extends Array<ListIndex> implements OrderedStringList {
|
|||
return a;
|
||||
}
|
||||
for (const str of source) {
|
||||
let index = new ListIndex(sections.strs.allocString(str, opts, sections));
|
||||
const index = new ListIndex(sections.strs.allocString(str, opts, sections));
|
||||
a.push(index);
|
||||
}
|
||||
return a;
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ export interface UnicodeSetParser {
|
|||
* @param pattern string to parse such as `[a-z]`
|
||||
* @param rangeCount number of ranges to allow for
|
||||
*/
|
||||
parseUnicodeSet(pattern: string, rangeCount: number) : UnicodeSet | null;
|
||||
parseUnicodeSet(pattern: string, rangeCount: number, x?: any) : UnicodeSet | null;
|
||||
/**
|
||||
* Calculate the number of ranges in a UnicodeSet
|
||||
* @param pattern string to parse such as `[a-z]`
|
||||
* @returns number of ranges, or -1 (with callback-reported err) on err
|
||||
*/
|
||||
sizeUnicodeSet(pattern: string) : number;
|
||||
sizeUnicodeSet(pattern: string, x?: any) : number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,18 +5,6 @@
|
|||
|
||||
/****************************** Lexical Models ******************************/
|
||||
|
||||
/**
|
||||
* A JavaScript string with the restriction that it must only
|
||||
* contain Unicode scalar values.
|
||||
*
|
||||
* This means that any lone high surrogate must be paired with
|
||||
* a low surrogate, if it exists. Lone surrogate code units are
|
||||
* forbidden.
|
||||
*
|
||||
* See also: https://developer.mozilla.org/en-US/docs/Web/API/USVString
|
||||
*/
|
||||
export type USVString = string;
|
||||
|
||||
export type CasingForm = 'lower' | 'initial' | 'upper';
|
||||
|
||||
/**
|
||||
|
|
@ -67,7 +55,7 @@ export interface LexiconTraversal {
|
|||
* - If `char` = 'e', the child represents a prefix of 'the'.
|
||||
* - Then `traversal` allows traversing the part of the lexicon prefixed by 'the'.
|
||||
*/
|
||||
children(): Generator<{char: USVString, traversal: () => LexiconTraversal}>;
|
||||
children(): Generator<{char: string, traversal: () => LexiconTraversal}>;
|
||||
|
||||
/**
|
||||
* Allows direct access to the traversal state that results when appending one
|
||||
|
|
@ -81,7 +69,7 @@ export interface LexiconTraversal {
|
|||
* That is, if a model "keys" `è` to `e`, there will be no `è` child.
|
||||
* @param char
|
||||
*/
|
||||
child(char: USVString): LexiconTraversal | undefined;
|
||||
child(char: string): LexiconTraversal | undefined;
|
||||
|
||||
/**
|
||||
* Any entries directly keyed by the currently-represented lookup prefix. Entries and
|
||||
|
|
@ -178,7 +166,7 @@ export interface LexicalModel {
|
|||
* @param text The original input text.
|
||||
* @returns The 'keyed' form of that text.
|
||||
*/
|
||||
toKey?(text: USVString): USVString;
|
||||
toKey?(text: string): string;
|
||||
|
||||
/**
|
||||
* Generates predictive suggestions corresponding to the state of context after the proposed
|
||||
|
|
@ -248,7 +236,7 @@ export interface LexicalModel {
|
|||
* @param context
|
||||
* @deprecated
|
||||
*/
|
||||
wordbreak?(context: Context): USVString;
|
||||
wordbreak?(context: Context): string;
|
||||
|
||||
/**
|
||||
* Lexical models _may_ provide a LexiconTraversal object usable to enhance
|
||||
|
|
@ -279,7 +267,7 @@ export interface Transform {
|
|||
*
|
||||
* Corresponds to `s` in com.keyman.KeyboardInterface.output.
|
||||
*/
|
||||
insert: USVString;
|
||||
insert: string;
|
||||
|
||||
/**
|
||||
* The number of code units to delete to the left of the cursor.
|
||||
|
|
@ -380,7 +368,7 @@ export interface Context {
|
|||
* buffer. If there is nothing to the left of the buffer, this is
|
||||
* an empty string.
|
||||
*/
|
||||
readonly left: USVString;
|
||||
readonly left: string;
|
||||
|
||||
/**
|
||||
* Up to maxRightContextCodeUnits code units of Unicode scalar value
|
||||
|
|
@ -390,7 +378,7 @@ export interface Context {
|
|||
*
|
||||
* This property may be missing entirely.
|
||||
*/
|
||||
readonly right?: USVString;
|
||||
readonly right?: string;
|
||||
|
||||
/**
|
||||
* Whether the insertion point is at the start of the buffer.
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ export { MATCH_HEX_ESCAPE, CONTAINS_QUAD_ESCAPE, MATCH_QUAD_ESCAPE };
|
|||
* @param x Name of element to box
|
||||
*/
|
||||
export function boxXmlArray(o: any, x: string): void {
|
||||
if(typeof o == 'object' && !Array.isArray(o[x])) {
|
||||
if(o[x] === null || o[x] === undefined) {
|
||||
if (typeof o == 'object' && !Array.isArray(o[x])) {
|
||||
if (o[x] === null || o[x] === undefined) {
|
||||
o[x] = [];
|
||||
}
|
||||
else {
|
||||
|
|
@ -64,7 +64,7 @@ export function unescapeQuadString(s: string): string {
|
|||
* @returns
|
||||
*/
|
||||
export function unescapeString(s: string): string {
|
||||
if(!s) {
|
||||
if (!s) {
|
||||
return s;
|
||||
}
|
||||
try {
|
||||
|
|
@ -74,13 +74,13 @@ export function unescapeString(s: string): string {
|
|||
* @param matched the entire match such as '0127' or '22 22'
|
||||
* @returns the unescaped match
|
||||
*/
|
||||
function processMatch(str: string, matched: string) : string {
|
||||
function processMatch(str: string, matched: string): string {
|
||||
const codepoints = matched.split(' ');
|
||||
const unescaped = codepoints.map(unescapeOne);
|
||||
return unescaped.join('');
|
||||
}
|
||||
s = s.replaceAll(MATCH_HEX_ESCAPE, processMatch);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
if (e instanceof RangeError) {
|
||||
throw new UnescapeError(`Out of range while unescaping '${s}': ${e.message}`, { cause: e });
|
||||
/* c8 ignore next 3 */
|
||||
|
|
@ -142,7 +142,7 @@ function regexOne(hex: string): string {
|
|||
/**
|
||||
* Escape a string (\uxxxx form) if there are any problematic codepoints
|
||||
*/
|
||||
export function escapeStringForRegex(s: string) : string {
|
||||
export function escapeStringForRegex(s: string): string {
|
||||
return s.split('').map(ch => escapeRegexCharIfSyntax(ch)).join('');
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ export function escapeStringForRegex(s: string) : string {
|
|||
* @returns
|
||||
*/
|
||||
export function unescapeStringToRegex(s: string): string {
|
||||
if(!s) {
|
||||
if (!s) {
|
||||
return s;
|
||||
}
|
||||
try {
|
||||
|
|
@ -162,13 +162,13 @@ export function unescapeStringToRegex(s: string): string {
|
|||
* @param matched the entire match such as '0127' or '22 22'
|
||||
* @returns the unescaped match
|
||||
*/
|
||||
function processMatch(str: string, matched: string) : string {
|
||||
function processMatch(str: string, matched: string): string {
|
||||
const codepoints = matched.split(' ');
|
||||
const unescaped = codepoints.map(regexOne);
|
||||
return unescaped.join('');
|
||||
}
|
||||
s = s.replaceAll(MATCH_HEX_ESCAPE, processMatch);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
if (e instanceof RangeError) {
|
||||
throw new UnescapeError(`Out of range while unescaping '${s}': ${e.message}`, { cause: e });
|
||||
/* c8 ignore next 3 */
|
||||
|
|
@ -181,19 +181,19 @@ export function unescapeStringToRegex(s: string): string {
|
|||
|
||||
/** True if this string *could* be a UTF-32 single char */
|
||||
export function
|
||||
isOneChar(value: string) : boolean {
|
||||
isOneChar(value: string): boolean {
|
||||
return [...value].length === 1;
|
||||
}
|
||||
|
||||
export function
|
||||
toOneChar(value: string) : number {
|
||||
toOneChar(value: string): number {
|
||||
if (!isOneChar(value)) {
|
||||
throw Error(`Not a single char: ${value}`);
|
||||
}
|
||||
return value.codePointAt(0);
|
||||
}
|
||||
|
||||
export function describeCodepoint(ch : number) : string {
|
||||
export function describeCodepoint(ch: number): string {
|
||||
let s;
|
||||
const p = BadStringAnalyzer.getProblem(ch);
|
||||
if (p != null) {
|
||||
|
|
@ -207,13 +207,85 @@ export function describeCodepoint(ch : number) : string {
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief function to convert a numeric character reference to a unicode codepoint e.g. c -> U+0063; 􏘁 -> U+10F601
|
||||
* @param instr the value that will converted
|
||||
* @return a unicode codepoint if instr is a numeric character reference
|
||||
* instr if instr is not a numeric character reference
|
||||
* @brief function to convert a Html-Entity Hex value to a unicode character e.g. c -> c; 😎 -> 😎
|
||||
* @param hex_Entity the value that will converted
|
||||
* @return a unicode character or undefined if in_str is not recognized
|
||||
*/
|
||||
export function decodeHexEntity(hex_Entity: string) {
|
||||
const hex = hex_Entity.replace('&#x', '').replace(';', '');
|
||||
if (hex_Entity.length > 9)
|
||||
return undefined;
|
||||
else
|
||||
return String.fromCodePoint(parseInt(hex, 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to convert a Html-Entity decimal value value to a unicode character e.g. c -> c; 😎 -> 😎
|
||||
* @param dec_Entity the value that will converted
|
||||
* @return a unicode character or undefined if in_str is not recognized
|
||||
*/
|
||||
export function decodeDecEntity(dec_Entity: string) {
|
||||
const dec = dec_Entity.replace('&#', '').replace(';', '');
|
||||
if (dec_Entity.length > 9)
|
||||
return undefined;
|
||||
else
|
||||
return String.fromCodePoint(parseInt(dec, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to convert a unicode hex value to a unicode character e.g. U+0063 -> c; U+1F60E; -> 😎
|
||||
* @param Uni_Val the value that will converted
|
||||
* @return a unicode character or undefined if in_str is not recognized
|
||||
*/
|
||||
export function decodeUniHexValue(Uni_Val: string): any {
|
||||
const hexval = Uni_Val.replace('U+', '0x');
|
||||
if (Uni_Val.length > 8)
|
||||
return undefined;
|
||||
else
|
||||
return String.fromCodePoint(parseInt(hexval, 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to convert a numeric character reference or a unicode value to a unicode character e.g. c -> c; U+1F60E -> 😎
|
||||
* @param in_str the value that will converted
|
||||
* @return a unicode character or undefined if in_str is not recognized
|
||||
*/
|
||||
export function convertToUnicodeCharacter(in_str: string): string {
|
||||
|
||||
if ((in_str === null) || (in_str === undefined)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
else if (in_str.substring(0, 3) === "&#x") {
|
||||
return decodeHexEntity(in_str);
|
||||
}
|
||||
|
||||
else if (in_str.substring(0, 2) === "&#") {
|
||||
return decodeDecEntity(in_str);
|
||||
}
|
||||
|
||||
else if (in_str.substring(0, 1) === "&") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
else if (in_str.substring(0, 2) === "U+") {
|
||||
return decodeUniHexValue(in_str);
|
||||
}
|
||||
|
||||
else if ( [...new Intl.Segmenter().segment(in_str)].length <= 1) {
|
||||
return in_str;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function convertToUnicodeCodePoint(instr: string): string {
|
||||
|
||||
if ((instr === null) || (instr === undefined)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (instr.substring(0, 3) === "&#x") {
|
||||
const num_length = instr.length - instr.indexOf("x") - 1;
|
||||
const num_str = instr.substring(instr.indexOf("x") + 1, instr.length - 1);
|
||||
|
|
@ -251,26 +323,26 @@ const Uni_FFFE_NONCHARACTER = 0xFFFE;
|
|||
const Uni_PLANE_MASK = 0x1F0000;
|
||||
const Uni_MAX_CODEPOINT = 0x10FFFF;
|
||||
// plane 0, 15, and 16 PUA
|
||||
const Uni_PUA_00_START = 0xE000;
|
||||
const Uni_PUA_00_END = 0xF8FF;
|
||||
const Uni_PUA_00_START = 0xE000;
|
||||
const Uni_PUA_00_END = 0xF8FF;
|
||||
const Uni_PUA_15_START = 0x0F0000;
|
||||
const Uni_PUA_15_END = 0x0FFFFD;
|
||||
const Uni_PUA_15_END = 0x0FFFFD;
|
||||
const Uni_PUA_16_START = 0x100000;
|
||||
const Uni_PUA_16_END = 0x10FFFD;
|
||||
const Uni_PUA_16_END = 0x10FFFD;
|
||||
|
||||
|
||||
/**
|
||||
* @brief True if a lead surrogate
|
||||
* \def Uni_IsSurrogate1
|
||||
*/
|
||||
export function Uni_IsSurrogate1(ch : number) {
|
||||
export function Uni_IsSurrogate1(ch: number) {
|
||||
return ((ch) >= Uni_LEAD_SURROGATE_START && (ch) <= Uni_LEAD_SURROGATE_END);
|
||||
}
|
||||
/**
|
||||
* @brief True if a trail surrogate
|
||||
* \def Uni_IsSurrogate2
|
||||
*/
|
||||
export function Uni_IsSurrogate2(ch : number) {
|
||||
export function Uni_IsSurrogate2(ch: number) {
|
||||
return ((ch) >= Uni_TRAIL_SURROGATE_START && (ch) <= Uni_TRAIL_SURROGATE_END);
|
||||
}
|
||||
|
||||
|
|
@ -278,19 +350,19 @@ export function Uni_IsSurrogate2(ch : number) {
|
|||
* @brief True if any surrogate
|
||||
* \def UniIsSurrogate
|
||||
*/
|
||||
export function Uni_IsSurrogate(ch : number) {
|
||||
export function Uni_IsSurrogate(ch: number) {
|
||||
return (Uni_IsSurrogate1(ch) || Uni_IsSurrogate2(ch));
|
||||
}
|
||||
|
||||
function Uni_IsEndOfPlaneNonCharacter(ch : number) {
|
||||
function Uni_IsEndOfPlaneNonCharacter(ch: number) {
|
||||
return (((ch) & Uni_FFFE_NONCHARACTER) == Uni_FFFE_NONCHARACTER); // matches FFFF or FFFE
|
||||
}
|
||||
|
||||
function Uni_IsNoncharacter(ch : number) {
|
||||
function Uni_IsNoncharacter(ch: number) {
|
||||
return (((ch) >= Uni_FD_NONCHARACTER_START && (ch) <= Uni_FD_NONCHARACTER_END) || Uni_IsEndOfPlaneNonCharacter(ch));
|
||||
}
|
||||
|
||||
function Uni_InCodespace(ch : number) {
|
||||
function Uni_InCodespace(ch: number) {
|
||||
return (ch >= 0 && ch <= Uni_MAX_CODEPOINT);
|
||||
};
|
||||
|
||||
|
|
@ -329,8 +401,8 @@ export function isPUA(ch: number) {
|
|||
}
|
||||
|
||||
/** @returns false if s is NEITHER NFC nor NFD. (Returns true for falsy) */
|
||||
export function isNormalized(s: string) : boolean {
|
||||
if(!s) return true; // empty or null
|
||||
export function isNormalized(s: string): boolean {
|
||||
if (!s) return true; // empty or null
|
||||
const nfc = s.normalize("NFC");
|
||||
const nfd = s.normalize("NFD");
|
||||
if (s !== nfc && s !== nfd) return false;
|
||||
|
|
@ -338,7 +410,7 @@ export function isNormalized(s: string) : boolean {
|
|||
}
|
||||
|
||||
class BadStringMap extends Map<BadStringType, Set<number>> {
|
||||
public toString() : string {
|
||||
public toString(): string {
|
||||
if (!this.size) {
|
||||
return "{}";
|
||||
}
|
||||
|
|
@ -349,7 +421,7 @@ class BadStringMap extends Map<BadStringType, Set<number>> {
|
|||
/** abstract class for analyzing and categorizing strings */
|
||||
export abstract class StringAnalyzer {
|
||||
/** add a string for analysis */
|
||||
public add(s : string) {
|
||||
public add(s: string) {
|
||||
for (const c of [...s]) {
|
||||
const ch = c.codePointAt(0);
|
||||
const problem = this.analyzeCodePoint(c, ch);
|
||||
|
|
@ -364,10 +436,10 @@ export abstract class StringAnalyzer {
|
|||
* @param c single codepoint to analyze (string)
|
||||
* @param ch single codepoint to analyze (scalar)
|
||||
*/
|
||||
protected abstract analyzeCodePoint(c: string, ch: number) : BadStringType;
|
||||
protected abstract analyzeCodePoint(c: string, ch: number): BadStringType;
|
||||
|
||||
/** internal interface for the result of an analysis */
|
||||
protected addProblem(ch : number, type : BadStringType) {
|
||||
protected addProblem(ch: number, type: BadStringType) {
|
||||
if (!this.m.has(type)) {
|
||||
this.m.set(type, new Set<number>());
|
||||
}
|
||||
|
|
@ -375,7 +447,7 @@ export abstract class StringAnalyzer {
|
|||
}
|
||||
|
||||
/** get the results of the analysis */
|
||||
public analyze() : BadStringMap {
|
||||
public analyze(): BadStringMap {
|
||||
if (this.m.size == 0) {
|
||||
return null;
|
||||
} else {
|
||||
|
|
@ -397,7 +469,7 @@ export class BadStringAnalyzer extends StringAnalyzer {
|
|||
public static getProblem(ch: number) {
|
||||
if (!isValidUnicode(ch)) {
|
||||
return BadStringType.illegal;
|
||||
} else if(isPUA(ch)) {
|
||||
} else if (isPUA(ch)) {
|
||||
return BadStringType.pua;
|
||||
} else { // TODO-LDML: unassigned
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -91,12 +91,12 @@ describe('Test of ElementString file', () => {
|
|||
});
|
||||
describe('Test of fromStrings()', () => {
|
||||
it('returns an empty ElementString if source is null', () => {
|
||||
const es = ElementString.fromStrings({}, null);
|
||||
const es = ElementString.fromStrings({}, {}, null);
|
||||
assert.deepEqual(es, new ElementString());
|
||||
});
|
||||
it('can create an ElementString from a string array', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(sections, ["𐌰", "𐌱", "𐌲"]);
|
||||
const actual = ElementString.fromStrings(sections, {}, ["𐌰", "𐌱", "𐌲"]);
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
|
|
@ -106,7 +106,7 @@ describe('Test of ElementString file', () => {
|
|||
});
|
||||
it('can create an ElementString from a string', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(sections, "𐌰𐌱𐌲");
|
||||
const actual = ElementString.fromStrings(sections, {}, "𐌰𐌱𐌲");
|
||||
const expected = [
|
||||
initElemElement(GOTHIC_A),
|
||||
initElemElement(GOTHIC_B),
|
||||
|
|
@ -118,6 +118,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
"1 2 3",
|
||||
);
|
||||
|
|
@ -132,6 +133,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
"1",
|
||||
);
|
||||
|
|
@ -146,6 +148,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
"1 2",
|
||||
);
|
||||
|
|
@ -160,6 +163,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
"1 A 3",
|
||||
);
|
||||
|
|
@ -174,6 +178,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1 2 3",
|
||||
|
|
@ -189,6 +194,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1",
|
||||
|
|
@ -204,6 +210,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1 2",
|
||||
|
|
@ -219,6 +226,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
"1 A 3",
|
||||
|
|
@ -234,6 +242,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
|
|
@ -250,6 +259,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
|
|
@ -266,6 +276,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
|
|
@ -282,6 +293,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
|
|
@ -299,6 +311,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
|
|
@ -316,6 +329,7 @@ describe('Test of ElementString file', () => {
|
|||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
const actual = ElementString.fromStrings(
|
||||
sections,
|
||||
{},
|
||||
"𐌰𐌱𐌲",
|
||||
null,
|
||||
null,
|
||||
|
|
@ -333,7 +347,7 @@ describe('Test of ElementString file', () => {
|
|||
ElementParser.segment = stubElementParserSegment_Uset;
|
||||
sections.strs.allocString = stubStrsAllocString_Str;
|
||||
sections.uset.allocUset = stubUsetAllocUset;
|
||||
const actual = ElementString.fromStrings(sections, "[𐌰-𐍊]");
|
||||
const actual = ElementString.fromStrings(sections, {}, "[𐌰-𐍊]");
|
||||
const expected = [
|
||||
initElemElement(
|
||||
new StrsItem(''),
|
||||
|
|
@ -348,17 +362,17 @@ describe('Test of ElementString file', () => {
|
|||
it('returns null for an invalid unicode set size', () => {
|
||||
ElementParser.segment = stubElementParserSegment_Uset;
|
||||
sections.usetparser.sizeUnicodeSet = (pattern: string) : number => -1;
|
||||
assert.isNull(ElementString.fromStrings(sections, "[𐌰-𐍊]"));
|
||||
assert.isNull(ElementString.fromStrings(sections, {}, "[𐌰-𐍊]"));
|
||||
});
|
||||
it('returns null if it cannot parse the unicode set', () => {
|
||||
ElementParser.segment = stubElementParserSegment_Uset;
|
||||
sections.usetparser.parseUnicodeSet = (pattern: string, rangeCount: number) : UnicodeSet | null => null;
|
||||
assert.isNull(ElementString.fromStrings(sections, "[𐌰-𐍊]"));
|
||||
assert.isNull(ElementString.fromStrings(sections, {}, "[𐌰-𐍊]"));
|
||||
});
|
||||
it('can handle quad strings', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Char;
|
||||
ElementParser.segment = stubElementParserSegment_Escaped;
|
||||
const actual = ElementString.fromStrings(sections, "\\ud800\\udf30");
|
||||
const actual = ElementString.fromStrings(sections, {}, "\\ud800\\udf30");
|
||||
const expected = [
|
||||
initElemElement(HI_GOTHIC_A),
|
||||
initElemElement(LO_GOTHIC_A),
|
||||
|
|
@ -367,7 +381,7 @@ describe('Test of ElementString file', () => {
|
|||
});
|
||||
it('can handle ElemElement of string type', () => {
|
||||
sections.strs.allocString = stubStrsAllocString_Str;
|
||||
const actual = ElementString.fromStrings(sections, ["𐌰𐌱𐌲",]);
|
||||
const actual = ElementString.fromStrings(sections, {}, ["𐌰𐌱𐌲",]);
|
||||
const expected = [
|
||||
initElemElement(
|
||||
new StrsItem("𐌰𐌱𐌲"),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { KMXPlus, LdmlKeyboardTypes, LexicalModelTypes } from "@keymanapp/common-types";
|
||||
|
||||
export let u: LexicalModelTypes.USVString;
|
||||
export let u: string;
|
||||
export let l: LexicalModelTypes.Transform;
|
||||
export let s: LexicalModelTypes.Suggestion;
|
||||
export let st: LexicalModelTypes.SuggestionTag;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ var
|
|||
KeymanRoot: string;
|
||||
ReportPath: string;
|
||||
begin
|
||||
if GetEnvironmentVariable('TEAMCITY_VERSION') <> '' then
|
||||
if GetEnvironmentVariable('TEAMCITY_GIT_PATH') <> '' then
|
||||
begin
|
||||
KeymanRoot := ExcludeTrailingPathDelimiter(GetEnvironmentVariable('KEYMAN_ROOT'));
|
||||
ReportPath := ExtractRelativePath(KeymanRoot, ExtractFilePath(ParamStr(0)) + 'dunitx-results.xml');
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue