Merge branch 'epic/kmc-convert' into feat/developer/kmc-convert
|
|
@ -19,7 +19,7 @@ AllowShortLambdasOnASingleLine: All
|
|||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: AllDefinitions
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
|
|
@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
|
|||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
|
|
|
|||
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -10,7 +10,7 @@ body:
|
|||
### Before you start
|
||||
|
||||
Before you submit this bug report, have you searched other reports for this bug?
|
||||
https://github.com/keymanapp/keyman/issues?q=is%3Aopen+is%3Aissue+label%3Abug
|
||||
https://github.com/keymanapp/keyman/issues?q=is%3Aissue+label%3Abug
|
||||
|
||||
* If you find a matching issue, go ahead and add a comment on that issue.
|
||||
* If you find related issues, make sure you list them below.
|
||||
|
|
|
|||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
|
|
@ -8,7 +8,7 @@ body:
|
|||
attributes:
|
||||
value: |
|
||||
Before you submit this feature request, have you searched existing requests?
|
||||
https://github.com/keymanapp/keyman/issues?q=is%3Aopen+is%3Aissue+label%3Afeat
|
||||
https://github.com/keymanapp/keyman/issues?q=is%3Aissue+label%3Afeat
|
||||
|
||||
* If you find a matching issue, go ahead and add a comment on that issue.
|
||||
* If you find related issues, make sure you list them below.
|
||||
|
|
|
|||
58
.github/actions/build-binary-packages/action.yml
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
name: build-binary-packages
|
||||
description: |
|
||||
Build binary packages
|
||||
inputs:
|
||||
dist:
|
||||
description: 'dist to build binary packages for'
|
||||
required: true
|
||||
arch:
|
||||
description: 'the architecture'
|
||||
required: false
|
||||
default: 'amd64'
|
||||
version:
|
||||
description: 'The Keyman version'
|
||||
required: true
|
||||
prerelease_tag:
|
||||
description: 'The prerelease tag'
|
||||
required: true
|
||||
deb_fullname:
|
||||
description: 'The full name used for the packages'
|
||||
required: true
|
||||
deb_email:
|
||||
description: 'The email address used for the packages'
|
||||
required: true
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
with:
|
||||
name: keyman-srcpkg
|
||||
path: artifacts/keyman-srcpkg
|
||||
|
||||
- name: Build
|
||||
uses: sillsdev/gha-ubuntu-packaging@7b56f50d5d5537e9e9cafd3f6139ec6da69cfcda # v1.1
|
||||
with:
|
||||
dist: "${{ inputs.dist }}"
|
||||
platform: "${{ inputs.arch }}"
|
||||
source_dir: "artifacts/keyman-srcpkg"
|
||||
sourcepackage: "keyman_${{ inputs.version }}-1.dsc"
|
||||
deb_fullname: ${{inputs.deb_fullname}}
|
||||
deb_email: ${{inputs.deb_email}}
|
||||
prerelease_tag: ${{ inputs.prerelease_tag }}
|
||||
|
||||
- name: Output resulting .deb files
|
||||
shell: bash
|
||||
run: |
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "$(find artifacts/ -name \*.deb)" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store binary packages
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
with:
|
||||
name: keyman-binarypkgs-${{ inputs.dist }}_${{ inputs.arch }}
|
||||
path: |
|
||||
artifacts/*
|
||||
!artifacts/keyman-srcpkg/
|
||||
if: always()
|
||||
6
.github/labeler.yml
vendored
|
|
@ -20,10 +20,8 @@ common/:
|
|||
- common/**
|
||||
- resources/**
|
||||
|
||||
common/models/: common/models/**
|
||||
common/models/types/: common/models/types/**
|
||||
common/models/templates/: common/models/templates/**
|
||||
common/models/wordbreakers/: common/models/wordbreakers/**
|
||||
common/models/templates/: web/src/engine/predictive-text/templates/**
|
||||
common/models/wordbreakers/: web/src/engine/predictive-text/wordbreakers/**
|
||||
|
||||
common/resources/: resources/**
|
||||
common/web/: common/web/**
|
||||
|
|
|
|||
21
.github/multi-labeler.yml
vendored
|
|
@ -15,24 +15,33 @@ labels:
|
|||
# conventional commit / semantic PR styles
|
||||
#
|
||||
|
||||
- label: 'feat'
|
||||
- label: 'auto'
|
||||
matcher:
|
||||
title: '^feat(\(|:)'
|
||||
- label: 'fix'
|
||||
title: '^auto(\(|:)'
|
||||
- label: 'change'
|
||||
matcher:
|
||||
title: '^fix(\(|:)'
|
||||
title: '^change(\(|:)'
|
||||
- label: 'chore'
|
||||
matcher:
|
||||
title: '^chore(\(|:)'
|
||||
- label: 'docs'
|
||||
matcher:
|
||||
title: '^docs(\(|:)'
|
||||
- label: 'feat'
|
||||
matcher:
|
||||
title: '^feat(\(|:)'
|
||||
- label: 'fix'
|
||||
matcher:
|
||||
title: '^fix(\(|:)'
|
||||
- label: 'refactor'
|
||||
matcher:
|
||||
title: '^refactor(\(|:)'
|
||||
- label: 'auto'
|
||||
- label: 'style'
|
||||
matcher:
|
||||
title: '^auto(\(|:)'
|
||||
title: '^style(\(|:)'
|
||||
- label: 'test'
|
||||
matcher:
|
||||
title: '^test(\(|:)'
|
||||
|
||||
#
|
||||
# additional meta flags
|
||||
|
|
|
|||
119
.github/workflows/api-verification.yml
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
name: "API Verification"
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Ubuntu packaging]
|
||||
types:
|
||||
- completed
|
||||
|
||||
env:
|
||||
STATUS_CONTEXT: 'API Verification'
|
||||
PKG_NAME: 'libkeymancore'
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
jobs:
|
||||
api_verification:
|
||||
name: Verify API for libkeymancore*.so
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
VERSION: ${{ steps.environment_step.outputs.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 }}
|
||||
IS_TEST_BUILD: ${{ steps.environment_step.outputs.IS_TEST_BUILD }}
|
||||
GIT_BRANCH: ${{ steps.environment_step.outputs.GIT_BRANCH }}
|
||||
GIT_BASE_BRANCH: ${{ steps.environment_step.outputs.GIT_BASE_BRANCH }}
|
||||
GIT_USER: ${{ steps.environment_step.outputs.GIT_USER }}
|
||||
|
||||
steps:
|
||||
- name: Restore artifacts
|
||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||
with:
|
||||
path: |
|
||||
artifacts
|
||||
key: artifacts-key-${{ github.event.workflow_run.id }}
|
||||
restore-keys: artifacts-key-
|
||||
|
||||
- name: Read environment
|
||||
id: environment_step
|
||||
run: |
|
||||
cat artifacts/env >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set pending status on PR builds
|
||||
id: set_status
|
||||
if: steps.environment_step.outputs.IS_TEST_BUILD == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
gh api \
|
||||
--method POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
/repos/$GITHUB_REPOSITORY/statuses/${{ steps.environment_step.outputs.GIT_SHA }} \
|
||||
-f state='pending' \
|
||||
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
|
||||
-f description='API verification started' \
|
||||
-f context="$STATUS_CONTEXT"
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
with:
|
||||
ref: '${{ steps.environment_step.outputs.GIT_SHA }}'
|
||||
fetch-depth: 0
|
||||
clean: false
|
||||
path: ${{ github.workspace }}/keyman/
|
||||
|
||||
- name: Install devscripts
|
||||
uses: ./keyman/.github/actions/apt-install
|
||||
with:
|
||||
packages: devscripts equivs
|
||||
|
||||
- name: "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 }})"
|
||||
run: |
|
||||
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")
|
||||
cd ${{ github.workspace }}/keyman/linux
|
||||
./scripts/deb-packaging.sh \
|
||||
--gha \
|
||||
--bin-pkg "${GITHUB_WORKSPACE}/artifacts/${BIN_PACKAGE}" \
|
||||
--git-sha "${{ steps.environment_step.outputs.GIT_SHA }}" \
|
||||
--git-base "${{ steps.environment_step.outputs.GIT_BASE }}" \
|
||||
verify 2>> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Archive .symbols file
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
with:
|
||||
name: libkeymancore.symbols
|
||||
path: ${{ github.workspace }}/keyman/linux/debian/tmp/DEBIAN/symbols
|
||||
if: always()
|
||||
|
||||
set_status:
|
||||
name: Set result status on PR builds
|
||||
needs: [api_verification]
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() && needs.api_verification.outputs.IS_TEST_BUILD == 'true' }}
|
||||
steps:
|
||||
- name: Set success
|
||||
if: needs.api_verification.result == 'success'
|
||||
run: |
|
||||
echo "RESULT=success" >> $GITHUB_ENV
|
||||
echo "MSG=Package build succeeded" >> $GITHUB_ENV
|
||||
|
||||
- name: Set cancelled
|
||||
if: needs.api_verification.result == 'cancelled'
|
||||
run: |
|
||||
echo "RESULT=error" >> $GITHUB_ENV
|
||||
echo "MSG=Package build cancelled" >> $GITHUB_ENV
|
||||
|
||||
- name: Set failure
|
||||
if: needs.api_verification.result == 'failure'
|
||||
run: |
|
||||
echo "RESULT=failure" >> $GITHUB_ENV
|
||||
echo "MSG=Package build failed" >> $GITHUB_ENV
|
||||
|
||||
- name: Set final status
|
||||
run: |
|
||||
gh api \
|
||||
--method POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
/repos/$GITHUB_REPOSITORY/statuses/${{ needs.api_verification.outputs.GIT_SHA }} \
|
||||
-f state="$RESULT" \
|
||||
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
|
||||
-f description="$MSG" \
|
||||
-f context="$STATUS_CONTEXT"
|
||||
126
.github/workflows/deb-packaging.yml
vendored
|
|
@ -24,13 +24,13 @@ jobs:
|
|||
sourcepackage:
|
||||
name: Build source package
|
||||
if: github.repository == 'keymanapp/keyman'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
VERSION: ${{ steps.version_step.outputs.VERSION }}
|
||||
PRERELEASE_TAG: ${{ steps.prerelease_tag.outputs.PRERELEASE_TAG }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c #v3.3.0
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
with:
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
|
||||
|
|
@ -109,52 +109,60 @@ jobs:
|
|||
debian/***/*
|
||||
if: always()
|
||||
|
||||
binary_packages:
|
||||
name: Build binary packages
|
||||
binary_packages_released:
|
||||
name: Build binary packages for released versions
|
||||
needs: sourcepackage
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
dist: [focal, jammy, mantic, noble]
|
||||
arch: [amd64]
|
||||
dist: [focal, jammy, noble]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
with:
|
||||
name: keyman-srcpkg
|
||||
path: artifacts/keyman-srcpkg
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
sparse-checkout: '.github/actions/'
|
||||
|
||||
- name: Build
|
||||
uses: sillsdev/gha-ubuntu-packaging@1f4b7e7eacb8c82a4d874ee2c371b9bfef7e16ea # v1.0
|
||||
uses: ./.github/actions/build-binary-packages
|
||||
with:
|
||||
dist: "${{ matrix.dist }}"
|
||||
platform: "${{ matrix.arch }}"
|
||||
source_dir: "artifacts/keyman-srcpkg"
|
||||
sourcepackage: "keyman_${{ needs.sourcepackage.outputs.VERSION }}-1.dsc"
|
||||
dist: ${{ matrix.dist }}
|
||||
version: ${{ needs.sourcepackage.outputs.VERSION }}
|
||||
prerelease_tag: ${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}
|
||||
deb_fullname: ${{env.DEBFULLNAME}}
|
||||
deb_email: ${{env.DEBEMAIL}}
|
||||
prerelease_tag: ${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}
|
||||
|
||||
- name: Output resulting .deb files
|
||||
run: |
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "$(find artifacts/ -name \*.deb)" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
binary_packages_unreleased:
|
||||
name: Build binary packages for next Ubuntu version
|
||||
needs: sourcepackage
|
||||
continue-on-error: true
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
dist: [oracular]
|
||||
|
||||
- name: Store binary packages
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
with:
|
||||
name: keyman-binarypkgs-${{ matrix.dist }}_${{ matrix.arch }}
|
||||
path: |
|
||||
artifacts/*
|
||||
!artifacts/keyman-srcpkg/
|
||||
if: always()
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
sparse-checkout: '.github/actions/'
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/build-binary-packages
|
||||
with:
|
||||
dist: ${{ matrix.dist }}
|
||||
version: ${{ needs.sourcepackage.outputs.VERSION }}
|
||||
prerelease_tag: ${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}
|
||||
deb_fullname: ${{env.DEBFULLNAME}}
|
||||
deb_email: ${{env.DEBEMAIL}}
|
||||
|
||||
autopkg_test:
|
||||
name: Run autopkgtests
|
||||
needs: [binary_packages]
|
||||
needs: [binary_packages_released]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
@ -183,10 +191,10 @@ jobs:
|
|||
|
||||
deb_signing:
|
||||
name: Sign source and binary packages
|
||||
needs: [sourcepackage, binary_packages]
|
||||
needs: [sourcepackage, binary_packages_released, binary_packages_unreleased]
|
||||
runs-on: ubuntu-latest
|
||||
environment: "deploy (linux)"
|
||||
if: github.event.client_payload.isTestBuild == 'false'
|
||||
if: ${{always() && needs.sourcepackage.result == 'success' && needs.binary_packages_released.result == 'success' && github.event.client_payload.isTestBuild == 'false'}}
|
||||
|
||||
steps:
|
||||
- name: Sign packages
|
||||
|
|
@ -283,69 +291,57 @@ jobs:
|
|||
done
|
||||
echo "::endgroup::"
|
||||
|
||||
api_verification:
|
||||
prepare_api_verification:
|
||||
name: Verify API for libkeymancore.so
|
||||
needs: [sourcepackage, binary_packages]
|
||||
needs: [sourcepackage, binary_packages_released]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
with:
|
||||
ref: '${{ github.event.client_payload.buildSha }}'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
|
||||
with:
|
||||
path: artifacts
|
||||
merge-multiple: true
|
||||
|
||||
- name: Install devscripts
|
||||
uses: ./.github/actions/apt-install
|
||||
with:
|
||||
packages: devscripts equivs
|
||||
|
||||
- name: Verify API
|
||||
- name: Save environment
|
||||
run: |
|
||||
cd linux
|
||||
# Extract line containing "Package: libkeymancore1" and then strip "Package: "
|
||||
PKG_NAME=$(grep -E 'Package: libkeymancore([0-9]+|$)' debian/control)
|
||||
PKG_NAME="${PKG_NAME#Package: }"
|
||||
./scripts/deb-packaging.sh \
|
||||
--gha \
|
||||
--bin-pkg "${GITHUB_WORKSPACE}/artifacts/${PKG_NAME}_${{ needs.sourcepackage.outputs.VERSION }}-1${{ needs.sourcepackage.outputs.PRERELEASE_TAG }}+jammy1_amd64.deb" \
|
||||
--git-sha "${{ github.event.client_payload.buildSha }}" \
|
||||
--git-base "${{ github.event.client_payload.baseRef }}" \
|
||||
verify 2>> $GITHUB_STEP_SUMMARY
|
||||
echo "VERSION=${{ needs.sourcepackage.outputs.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
|
||||
echo "IS_TEST_BUILD=${{ github.event.client_payload.isTestBuild }}" >> artifacts/env
|
||||
echo "GIT_BRANCH=${{ github.event.client_payload.branch }}" >> artifacts/env
|
||||
echo "GIT_BASE_BRANCH=${{ github.event.client_payload.baseBranch }}" >> artifacts/env
|
||||
echo "GIT_USER=${{ github.event.client_payload.user }}" >> artifacts/env
|
||||
|
||||
- name: Archive .symbols file
|
||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
||||
- name: Cache artifacts
|
||||
uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||
with:
|
||||
name: libkeymancore.symbols
|
||||
path: linux/debian/tmp/DEBIAN/symbols
|
||||
if: always()
|
||||
path: |
|
||||
artifacts
|
||||
key: artifacts-key-${{ github.run_id }}
|
||||
|
||||
# We intentionally ignore the results of binary_packages_unreleased
|
||||
set_status:
|
||||
name: Set result status on PR builds
|
||||
needs: [sourcepackage, binary_packages, api_verification, autopkg_test]
|
||||
needs: [sourcepackage, binary_packages_released, prepare_api_verification, autopkg_test]
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ always() && github.event.client_payload.isTestBuild == 'true' }}
|
||||
steps:
|
||||
- name: Set success
|
||||
if: needs.sourcepackage.result == 'success' && needs.binary_packages.result == 'success' && needs.api_verification.result == 'success' && needs.autopkg_test.result == 'success'
|
||||
if: needs.sourcepackage.result == 'success' && needs.binary_packages_released.result == 'success' && needs.prepare_api_verification.result == 'success' && needs.autopkg_test.result == 'success'
|
||||
run: |
|
||||
echo "RESULT=success" >> $GITHUB_ENV
|
||||
echo "MSG=Package build succeeded" >> $GITHUB_ENV
|
||||
|
||||
- name: Set cancelled
|
||||
if: needs.sourcepackage.result == 'cancelled' || needs.binary_packages.result == 'cancelled' || needs.api_verification.result == 'cancelled' || needs.autopkg_test.result == 'cancelled'
|
||||
if: needs.sourcepackage.result == 'cancelled' || needs.binary_packages_released.result == 'cancelled' || needs.prepare_api_verification.result == 'cancelled' || needs.autopkg_test.result == 'cancelled'
|
||||
run: |
|
||||
echo "RESULT=error" >> $GITHUB_ENV
|
||||
echo "MSG=Package build cancelled" >> $GITHUB_ENV
|
||||
|
||||
- name: Set failure
|
||||
if: needs.sourcepackage.result == 'failure' || needs.binary_packages.result == 'failure' || needs.api_verification.result == 'failure' || needs.autopkg_test.result == 'failure'
|
||||
if: needs.sourcepackage.result == 'failure' || needs.binary_packages_released.result == 'failure' || needs.prepare_api_verification.result == 'failure' || needs.autopkg_test.result == 'failure'
|
||||
run: |
|
||||
echo "RESULT=failure" >> $GITHUB_ENV
|
||||
echo "MSG=Package build failed" >> $GITHUB_ENV
|
||||
|
|
|
|||
9
.gitignore
vendored
|
|
@ -3,7 +3,6 @@
|
|||
/windows/debug/
|
||||
/windows/lib/
|
||||
/windows/release/
|
||||
/windows/src/PathDefines.mak
|
||||
/windows/src/**/*.err
|
||||
/windows/src/**/*.Build.CppClean.log
|
||||
/windows/src/**/*.dproj.local
|
||||
|
|
@ -184,11 +183,3 @@ lcov.info
|
|||
/keyman*.buildinfo
|
||||
/keyman*.changes
|
||||
/keyman*.tar.?z
|
||||
|
||||
#Sabine:
|
||||
# /common/test/keyboards/invalid/source/*.kmx
|
||||
# /developer/src/test/auto/kmcomp/*.kmn
|
||||
# /developer/src/test/auto/kmcomp/*.kvk
|
||||
# /developer/src/test/auto/kmcomp/*.kvk*
|
||||
# /developer/src/test/auto/kmcomp/*.txt
|
||||
/linux/mcompile/keymap/X_bak
|
||||
|
|
|
|||
|
|
@ -379,12 +379,18 @@ group.
|
|||
|
||||
| Label name | `keyman` :mag_right: | Description |
|
||||
| --- | --- | --- |
|
||||
| `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. |
|
||||
| `docs` | [search][search-docs] | Relating to any type of documentation. |
|
||||
| `feat` | [search][search-feat] | Feature requests. |
|
||||
| `bug` | [search][search-bug] | Confirmed bugs or reports that are very likely to be bugs. |
|
||||
| `chore` | [search][search-chore] | Minor updates to Keyman. |
|
||||
| `fix` | [search][search-fix] | For PRs only: a bug fix, corresponds to issue label `bug`. |
|
||||
| `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. |
|
||||
| `docs` | [search][search-docs] | Related to any type of documentation. |
|
||||
| `style` | [search][search-style] | Code formatting only. |
|
||||
| `test` | [search][search-test] | Relating to automated tests. |
|
||||
|
||||
#### Issue State
|
||||
|
||||
|
|
@ -397,7 +403,6 @@ group.
|
|||
| `low-priority` | [search][search-low-priority] | The Keyman core team has decided not to fix these issues for now, but may in the future as time permits. |
|
||||
| `wontfix` | [search][search-wontfix] | The Keyman core team has decided not to fix these issues for now, either because they're working as intended or for some other reason. |
|
||||
| `invalid` | [search][search-invalid] | Issues which aren't valid (e.g. user errors). |
|
||||
| `auto` | [search][search-auto] | Pull requests created automatically, e.g. version increments. |
|
||||
| `compatibility` | [search][search-compatibility] | Related to interactions with other applications. |
|
||||
| `dependencies` | [search][search-dependencies] | Related to changes in dependencies, often automatically generated. |
|
||||
| `external` | [search][search-external] | Related to issues that require changes to third party applications in order to be resolved. |
|
||||
|
|
@ -408,15 +413,16 @@ These labels also include sublabels, such as `windows/config/`.
|
|||
|
||||
| Label name | `keyman` :mag_right: | Description |
|
||||
| --- | --- | --- |
|
||||
| `windows/` | [search][search-windows] | Related to Keyman running on Windows. |
|
||||
| `android/` | [search][search-android] | Related to Keyman running on Android. |
|
||||
| `common/` | [search][search-common] | Related to shared code. |
|
||||
| `core/` | [search][search-core] | Related to Keyman Core. |
|
||||
| `developer/` | [search][search-developer] | Related to Keyman Developer. |
|
||||
| `ios/` | [search][search-ios] | Related to Keyman running on iOS. |
|
||||
| `linux/` | [search][search-linux] | Related to Keyman running on Linux. |
|
||||
| `mac/` | [search][search-mac] | Related to Keyman running on macOS. |
|
||||
| `ios/` | [search][search-ios] | Related to Keyman running on iOS. |
|
||||
| `android/` | [search][search-android] | Related to Keyman running on Android. |
|
||||
| `web/` | [search][search-web] | Related to KeymanWeb. |
|
||||
| `developer/` | [search][search-developer] | Related to Keyman Developer. |
|
||||
| `common/` | [search][search-common] | Related to Keyman Core and shared code. |
|
||||
| `oem/` | [search][search-oem] | Related to third party projects that are built together with Keyman. |
|
||||
| `web/` | [search][search-web] | Related to KeymanWeb. |
|
||||
| `windows/` | [search][search-windows] | Related to Keyman running on Windows. |
|
||||
|
||||
#### Pull Request Labels
|
||||
|
||||
|
|
@ -428,12 +434,17 @@ These labels also include sublabels, such as `windows/config/`.
|
|||
| `user-test-required` | [search][search-user-test-required] | Pull requests where user testing is incomplete. |
|
||||
|
||||
|
||||
[search-feat]: https://github.com/keymanapp/keyman/labels/feat
|
||||
[search-auto]: https://github.com/keymanapp/keyman/labels/auto
|
||||
[search-bug]: https://github.com/keymanapp/keyman/labels/bug
|
||||
[search-change]: https://github.com/keymanapp/keyman/labels/change
|
||||
[search-chore]: https://github.com/keymanapp/keyman/labels/chore
|
||||
[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-question]: https://github.com/keymanapp/keyman/labels/question
|
||||
[search-spec]: https://github.com/keymanapp/keyman/labels/spec
|
||||
[search-docs]: https://github.com/keymanapp/keyman/labels/docs
|
||||
[search-style]: https://github.com/keymanapp/keyman/labels/style
|
||||
[search-test]: https://github.com/keymanapp/keyman/labels/test
|
||||
|
||||
[search-requires-design-work]: https://github.com/keymanapp/keyman/labels/requires-design-work
|
||||
[search-help-wanted]: https://github.com/keymanapp/keyman/labels/help%20wanted
|
||||
|
|
@ -443,20 +454,20 @@ These labels also include sublabels, such as `windows/config/`.
|
|||
[search-wontfix]: https://github.com/keymanapp/keyman/labels/wontfix
|
||||
[search-invalid]: https://github.com/keymanapp/keyman/labels/invalid
|
||||
|
||||
[search-auto]: https://github.com/keymanapp/keyman/labels/auto
|
||||
[search-compatibility]: https://github.com/keymanapp/keyman/labels/compatibility
|
||||
[search-dependencies]: https://github.com/keymanapp/keyman/labels/dependencies
|
||||
[search-external]: https://github.com/keymanapp/keyman/labels/external
|
||||
|
||||
[search-windows]: https://github.com/keymanapp/keyman/labels/windows%2F
|
||||
[search-android]: https://github.com/keymanapp/keyman/labels/android%2F
|
||||
[search-common]: https://github.com/keymanapp/keyman/labels/common%2F
|
||||
[search-core]: https://github.com/keymanapp/keyman/labels/core%2F
|
||||
[search-developer]: https://github.com/keymanapp/keyman/labels/developer%2F
|
||||
[search-ios]: https://github.com/keymanapp/keyman/labels/ios%2F
|
||||
[search-linux]: https://github.com/keymanapp/keyman/labels/linux%2F
|
||||
[search-mac]: https://github.com/keymanapp/keyman/labels/mac%2F
|
||||
[search-ios]: https://github.com/keymanapp/keyman/labels/ios%2F
|
||||
[search-android]: https://github.com/keymanapp/keyman/labels/android%2F
|
||||
[search-web]: https://github.com/keymanapp/keyman/labels/web%2F
|
||||
[search-developer]: https://github.com/keymanapp/keyman/labels/developer%2F
|
||||
[search-common]: https://github.com/keymanapp/keyman/labels/common%2F
|
||||
[search-oem]: https://github.com/keymanapp/keyman/labels/oem%2F
|
||||
[search-web]: https://github.com/keymanapp/keyman/labels/web%2F
|
||||
[search-windows]: https://github.com/keymanapp/keyman/labels/windows%2F
|
||||
|
||||
[search-cherry-pick]: https://github.com/keymanapp/keyman/labels/cherry-pick
|
||||
[search-refactor]: https://github.com/keymanapp/keyman/labels/refactor
|
||||
|
|
|
|||
1073
HISTORY.md
|
|
@ -1,6 +1,6 @@
|
|||
# License
|
||||
|
||||
Copyright (c) 2017-2022 SIL International. All rights reserved.
|
||||
Copyright (c) 2017-2024 SIL Global. All rights reserved.
|
||||
|
||||
Licensed under the MIT License.
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ Licensed under the MIT License.
|
|||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2017-2022 SIL International
|
||||
Copyright (c) 2017-2024 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
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# License
|
||||
|
||||
Copyright (c) SIL International.
|
||||
Copyright (c) SIL Global.
|
||||
|
||||
Keyman is an open source project distributed under the [MIT license](LICENSE.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
18.0.15
|
||||
18.0.111
|
||||
2
android/.gitignore
vendored
|
|
@ -37,8 +37,6 @@ KMEA/**/assets/keymanandroid.js
|
|||
KMEA/**/assets/keyman.js.map
|
||||
KMEA/**/assets/keymanweb-webview.js
|
||||
KMEA/**/assets/keymanweb-webview.js.map
|
||||
KMEA/**/assets/keymanweb-webview.es5.js
|
||||
KMEA/**/assets/keymanweb-webview.es5.js.map
|
||||
KMEA/**/assets/map-polyfill.js
|
||||
KMEA/**/assets/sentry.min.js
|
||||
KMEA/**/assets/keyman-sentry.js
|
||||
|
|
|
|||
|
|
@ -2,25 +2,27 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
flatDir {
|
||||
dirs "kMAPro/libs/com/stepstone/stepper/material-stepper/4.3.1/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.0'
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
// sentry-android-gradle-plugin 2.1.5+ requires AGP 7.0
|
||||
classpath 'io.sentry:sentry-android-gradle-plugin:2.1.2'
|
||||
classpath 'io.sentry:sentry-android-gradle-plugin:4.6.0'
|
||||
classpath 'name.remal:gradle-plugins:1.5.0'
|
||||
|
||||
// From jcenter() which could be sunset in future
|
||||
// From jcenter() which was deprecated August 2024
|
||||
// https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/
|
||||
classpath 'com.stepstone.stepper:material-stepper:4.3.1'
|
||||
classpath 'com.stepstone.stepper:material-stepper:4.3.1@aar'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url uri("${projectDir}/libs") }
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,16 @@
|
|||
#!/usr/bin/env bash
|
||||
# Build Keyman for Android app (KMAPro)
|
||||
|
||||
# set -x
|
||||
set -eu
|
||||
|
||||
## START STANDARD BUILD SCRIPT INCLUDE
|
||||
# adjust relative paths as necessary
|
||||
THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
|
||||
. "${THIS_SCRIPT%/*}/../../resources/build/build-utils.sh"
|
||||
. "${THIS_SCRIPT%/*}/../../resources/build/builder.inc.sh"
|
||||
## END STANDARD BUILD SCRIPT INCLUDE
|
||||
|
||||
. "$KEYMAN_ROOT/resources/shellHelperFunctions.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-help.inc.sh"
|
||||
. "$KEYMAN_ROOT/resources/build/build-download-resources.sh"
|
||||
|
||||
# This script runs from its own folder
|
||||
cd "$THIS_SCRIPT_PATH"
|
||||
. "$KEYMAN_ROOT/android/KMAPro/build-play-store-notes.inc.sh"
|
||||
|
||||
# ################################ Main script ################################
|
||||
|
||||
|
|
@ -32,6 +27,7 @@ builder_describe "Builds Keyman for Android app." \
|
|||
"configure" \
|
||||
"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"
|
||||
|
||||
|
|
@ -116,3 +112,13 @@ if builder_start_action test; then
|
|||
|
||||
builder_finish_action success test
|
||||
fi
|
||||
|
||||
if builder_start_action publish; then
|
||||
# Copy Release Notes
|
||||
generateReleaseNotes
|
||||
|
||||
# Publish symbols and Keyman for Android to Play Store
|
||||
./gradlew $DAEMON_FLAG publishSentry publishReleaseApk
|
||||
|
||||
builder_finish_action success publish
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ plugins {
|
|||
id 'com.android.application'
|
||||
id 'io.sentry.android.gradle'
|
||||
// https://github.com/Triple-T/gradle-play-publisher/issues/947#issuecomment-843634852
|
||||
id 'com.github.triplet.play' version '3.8.1' apply false
|
||||
id 'com.github.triplet.play' version '3.9.1' apply false
|
||||
id 'name.remal.default-plugins'
|
||||
}
|
||||
|
||||
|
|
@ -105,12 +105,17 @@ android {
|
|||
}
|
||||
|
||||
// how to configure the sentry android gradle plugin
|
||||
sentry {
|
||||
// Disables or enables the automatic configuration of Native symbols
|
||||
uploadNativeSymbols = true
|
||||
task publishSentry {
|
||||
doLast {
|
||||
println 'Publishing Keyman symbols to Sentry'
|
||||
sentry {
|
||||
// Disables or enables the automatic configuration of Native symbols
|
||||
uploadNativeSymbols = true
|
||||
|
||||
// Does or doesn't include the source code of native code for Sentry
|
||||
includeNativeSources = true
|
||||
// Does or doesn't include the source code of native code for Sentry
|
||||
includeNativeSources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String env_keys_json_file = System.getenv("keys_json_file")
|
||||
|
|
@ -145,17 +150,16 @@ repositories {
|
|||
dirs 'libs'
|
||||
}
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.6.0-rc01'
|
||||
implementation 'com.google.android.material:material:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'com.stepstone.stepper:material-stepper:4.3.1'
|
||||
api(name: 'keyman-engine', ext: 'aar')
|
||||
implementation 'io.sentry:sentry-android:6.9.2'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'io.sentry:sentry-android:7.8.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
implementation "com.android.installreferrer:installreferrer:2.2"
|
||||
|
||||
// Add dependency for generating QR Codes
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.stepstone.stepper</groupId>
|
||||
<artifactId>material-stepper</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<packaging>aar</packaging>
|
||||
<name>Android Material Stepper</name>
|
||||
<description>This library allows to use Material steppers inside Android applications.</description>
|
||||
<url>https://github.com/stepstone-tech/android-material-stepper</url>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>zawadz88</id>
|
||||
<name>Piotr Zawadzki</name>
|
||||
<email>piotr.zawadzki@stepstone.com</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>https://github.com/stepstone-tech/android-material-stepper.git</connection>
|
||||
<developerConnection>https://github.com/stepstone-tech/android-material-stepper.git</developerConnection>
|
||||
<url>https://github.com/stepstone-tech/android-material-stepper</url>
|
||||
</scm>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.android.support</groupId>
|
||||
<artifactId>appcompat-v7</artifactId>
|
||||
<version>25.4.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>2.7.21</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.assertj</groupId>
|
||||
<artifactId>assertj-android</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.robolectric</groupId>
|
||||
<artifactId>robolectric</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jre7</artifactId>
|
||||
<version>1.1.4-3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<version>1.1.4-3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nhaarman</groupId>
|
||||
<artifactId>mockito-kotlin</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -7,6 +7,10 @@
|
|||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<!-- API 33 and above -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
|
||||
<!-- Devices running up to Android 12L
|
||||
Starting in API level 33, this permission has no effect:
|
||||
https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE -->
|
||||
|
|
@ -293,6 +297,11 @@
|
|||
android:configChanges="orientation"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.Base" />
|
||||
<activity
|
||||
android:name=".AdjustLongpressDelayActivity"
|
||||
android:configChanges="orientation"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.Base" />
|
||||
|
||||
<!-- Put other WebViewActivities in a separate process so the Keyboard WebView doesn't lag.
|
||||
Ref https://stackoverflow.com/questions/40650643/timed-out-waiting-on-iinputcontextcallback-with-custom-keyboard-on-android -->
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package com.keyman.android;
|
||||
|
||||
import com.tavultesoft.kmapro.AdjustLongpressDelayActivity;
|
||||
import com.tavultesoft.kmapro.BuildConfig;
|
||||
import com.tavultesoft.kmapro.DefaultLanguageResource;
|
||||
import com.tavultesoft.kmapro.KeymanSettingsActivity;
|
||||
|
|
@ -42,6 +43,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
private static View inputView = null;
|
||||
private static ExtractedText exText = null;
|
||||
private KMHardwareKeyboardInterpreter interpreter = null;
|
||||
private int lastOrientation = Configuration.ORIENTATION_UNDEFINED;
|
||||
|
||||
private static final String TAG = "SystemKeyboard";
|
||||
|
||||
|
|
@ -56,6 +58,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
if (DependencyUtil.libraryExists(LibraryType.SENTRY) && !Sentry.isEnabled()) {
|
||||
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);
|
||||
});
|
||||
|
|
@ -129,7 +132,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
@Override
|
||||
public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
|
||||
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, candidatesEnd);
|
||||
KMManager.updateSelectionRange(KMManager.KeyboardType.KEYBOARD_TYPE_SYSTEM, newSelStart, newSelEnd);
|
||||
KMManager.updateSelectionRange(KMManager.KeyboardType.KEYBOARD_TYPE_SYSTEM);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -145,6 +148,16 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
KMManager.onStartInput(attribute, restarting);
|
||||
KMManager.resetContext(KeyboardType.KEYBOARD_TYPE_SYSTEM);
|
||||
|
||||
// This method (likely) includes the IME equivalent to `onResume` for `Activity`-based classes,
|
||||
// making it an important time to detect orientation changes.
|
||||
Context appContext = getApplicationContext();
|
||||
int newOrientation = KMManager.getOrientation(appContext);
|
||||
if(newOrientation != lastOrientation) {
|
||||
lastOrientation = newOrientation;
|
||||
Configuration newConfig = this.getResources().getConfiguration();
|
||||
KMManager.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
// Temporarily disable predictions on certain fields (e.g. hidden password field or numeric)
|
||||
int inputType = attribute.inputType;
|
||||
KMManager.setMayPredictOverride(inputType);
|
||||
|
|
@ -152,7 +165,6 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
KMManager.setBannerOptions(false);
|
||||
} else if (KMManager.isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM)){
|
||||
// Check if predictions needs to be re-enabled per Settings preference
|
||||
Context appContext = getApplicationContext();
|
||||
Keyboard kbInfo = KMManager.getCurrentKeyboardInfo(appContext);
|
||||
if (kbInfo != null) {
|
||||
String langId = kbInfo.getLanguageID();
|
||||
|
|
@ -164,14 +176,20 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
}
|
||||
}
|
||||
|
||||
// Determine special handling for ENTER key
|
||||
KMManager.setEnterMode(attribute.imeOptions, inputType);
|
||||
|
||||
InputConnection ic = getCurrentInputConnection();
|
||||
if (ic != null) {
|
||||
ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
|
||||
if (icText != null) {
|
||||
/*
|
||||
We do sometimes receive null `icText.text`, even though
|
||||
getExtractedText() docs does not list this as a possible
|
||||
return value, so we test for that as well (#11479)
|
||||
*/
|
||||
if (icText != null && icText.text != null) {
|
||||
boolean didUpdateText = KMManager.updateText(KeyboardType.KEYBOARD_TYPE_SYSTEM, icText.text.toString());
|
||||
int selStart = icText.startOffset + icText.selectionStart;
|
||||
int selEnd = icText.startOffset + icText.selectionEnd;
|
||||
boolean didUpdateSelection = KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_SYSTEM, selStart, selEnd);
|
||||
boolean didUpdateSelection = KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_SYSTEM);
|
||||
if (!didUpdateText || !didUpdateSelection)
|
||||
exText = icText;
|
||||
}
|
||||
|
|
@ -194,12 +212,6 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
super.onUpdateExtractingVisibility(ei);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
KMManager.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigureWindow(Window win, boolean isFullscreen, boolean isCandidatesOnly) {
|
||||
super.onConfigureWindow(win, isFullscreen, isCandidatesOnly);
|
||||
|
|
@ -215,13 +227,12 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
super.onComputeInsets(outInsets);
|
||||
|
||||
// We should extend the touchable region so that Keyman sub keys menu can receive touch events outside the keyboard frame
|
||||
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||
Point size = new Point(0, 0);
|
||||
wm.getDefaultDisplay().getSize(size);
|
||||
Point size = KMManager.getWindowSize(getApplicationContext());
|
||||
|
||||
int inputViewHeight = 0;
|
||||
if (inputView != null)
|
||||
if (inputView != null) {
|
||||
inputViewHeight = inputView.getHeight();
|
||||
}
|
||||
|
||||
int bannerHeight = KMManager.getBannerHeight(this);
|
||||
int kbHeight = KMManager.getKeyboardHeight(this);
|
||||
|
|
@ -237,6 +248,8 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
if (exText != null)
|
||||
exText = null;
|
||||
}
|
||||
// Initialize keyboard options
|
||||
KMManager.sendOptionsToKeyboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Keyman is copyright (C) SIL International. MIT License.
|
||||
*
|
||||
* (Optional description of this file)
|
||||
*/
|
||||
package com.tavultesoft.kmapro;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.keyman.engine.BaseActivity;
|
||||
import com.keyman.engine.KMManager;
|
||||
|
||||
/**
|
||||
* Settings menu for adjusting the longpress delay time. The value for the current longpress delay time
|
||||
* is saved in shared preferences as an integer (milliseconds).
|
||||
*/
|
||||
public class AdjustLongpressDelayActivity extends BaseActivity {
|
||||
private static final String TAG = "AdjustLongpressDelay";
|
||||
public static final String adjustLongpressDelayKey = "AdjustLongpressDelay";
|
||||
|
||||
// Keeps track of the adjusted longpress delay time for saving.
|
||||
// Internally use milliseconds, but GUI displays seconds
|
||||
private static int currentDelayTimeMS = KMManager.KMDefault_LongpressDelay; // ms
|
||||
private static int delayTimeIncrement = 200; // ms
|
||||
|
||||
/**
|
||||
* Convert currentDelayTimeMS to progress
|
||||
* @return int
|
||||
*/
|
||||
private int delayTimeToProgress() {
|
||||
return (currentDelayTimeMS / delayTimeIncrement) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert progress to currentDelayTimeMS
|
||||
* @param progress
|
||||
* @return int (milliseconds)
|
||||
*/
|
||||
private int progressToDelayTime(int progress) {
|
||||
return (progress + 1) * delayTimeIncrement + 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Context context = this;
|
||||
|
||||
setContentView(R.layout.activity_adjust_longpress_delay);
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.titlebar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(null);
|
||||
actionBar.setDisplayUseLogoEnabled(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 adjustLongpressDelayActivityTitle = (TextView) findViewById(R.id.bar_title);
|
||||
|
||||
String titleStr = getString(R.string.adjust_longpress_delay);
|
||||
adjustLongpressDelayActivityTitle.setTextColor(ContextCompat.getColor(this, R.color.ms_white));
|
||||
adjustLongpressDelayActivityTitle.setText(titleStr);
|
||||
|
||||
currentDelayTimeMS = KMManager.getLongpressDelay();
|
||||
|
||||
TextView adjustLongpressDelayText = (TextView) findViewById(R.id.delayTimeText);
|
||||
String longpressDelayTextSeconds = String.format(getString(R.string.longpress_delay_time), (float)(currentDelayTimeMS/1000.0));
|
||||
adjustLongpressDelayText.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
|
||||
adjustLongpressDelayText.setText(longpressDelayTextSeconds);
|
||||
|
||||
final SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
|
||||
seekBar.setProgress(delayTimeToProgress());
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
// Update the text field.
|
||||
// The keyboard options will be saved and sent to KeymanWeb when exiting the menu
|
||||
currentDelayTimeMS = progressToDelayTime(progress);
|
||||
String longpressDelayTextSeconds = String.format(getString(R.string.longpress_delay_time), (float)(currentDelayTimeMS/1000.0));
|
||||
adjustLongpressDelayText.setText(longpressDelayTextSeconds);
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.delayTimeDownButton).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (currentDelayTimeMS > KMManager.KMMinimum_LongpressDelay) {
|
||||
currentDelayTimeMS -= delayTimeIncrement;
|
||||
seekBar.setProgress(delayTimeToProgress());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.delayTimeUpButton).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (currentDelayTimeMS < KMManager.KMMaximum_LongpressDelay) {
|
||||
currentDelayTimeMS += delayTimeIncrement;
|
||||
seekBar.setProgress(delayTimeToProgress());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Store the longpress delay as a reference
|
||||
// and then update KeymanWeb with the longpress delay
|
||||
KMManager.setLongpressDelay(currentDelayTimeMS);
|
||||
KMManager.sendOptionsToKeyboard();
|
||||
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -173,6 +173,7 @@ public class BookmarksActivity extends BaseActivity {
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
overridePendingTransition(0, android.R.anim.fade_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,19 @@ public class CheckPermissions {
|
|||
return permissionsOK;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
|
||||
permissionsOK = Environment.isExternalStorageManager();
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
|
||||
// TODO: Workout scoped storage permission #10659
|
||||
}
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
// < API 30
|
||||
permissionsOK = checkPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
// API 30-32
|
||||
permissionsOK = Environment.isExternalStorageManager() ||
|
||||
checkPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
} else {
|
||||
// API 33+
|
||||
//https://developer.android.com/about/versions/13/behavior-changes-13#granular-media-permissions
|
||||
// Manifest.permission.READ_MEDIA_AUDIO doesn't seem to be needed
|
||||
permissionsOK = permissionsOK && checkPermission(activity, Manifest.permission.READ_MEDIA_IMAGES);
|
||||
permissionsOK = permissionsOK && checkPermission(activity, Manifest.permission.READ_MEDIA_VIDEO);
|
||||
}
|
||||
|
||||
return permissionsOK;
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
|
|||
hashMap = new HashMap<>();
|
||||
final String customHelpLink = kbd.getHelpLink();
|
||||
// Check if app declared FileProvider
|
||||
icon = String.valueOf(R.drawable.ic_arrow_forward);
|
||||
icon = String.valueOf(R.drawable.ic_action_forward);
|
||||
// Don't show help link arrow if File Provider unavailable, or custom help doesn't exist
|
||||
if ( (customHelpLink != null && !FileProviderUtils.exists(context)) ||
|
||||
(customHelpLink == null && !packageID.equals(KMManager.KMDefault_UndefinedPackageID)) ) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
|
|||
private static Context context;
|
||||
|
||||
private Preference languagesPreference, installKeyboardOrDictionary, displayLanguagePreference,
|
||||
adjustKeyboardHeight;
|
||||
adjustKeyboardHeight, adjustLongpressDelay;
|
||||
private ListPreference spacebarTextPreference;
|
||||
private CheckBoxPreference setSystemKeyboardPreference;
|
||||
private CheckBoxPreference setDefaultKeyboardPreference;
|
||||
|
|
@ -99,6 +99,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
|
|||
});
|
||||
|
||||
setDefaultKeyboardPreference.setOnPreferenceChangeListener(checkBlocker);
|
||||
|
||||
adjustKeyboardHeight = new Preference(context);
|
||||
adjustKeyboardHeight.setKey(AdjustKeyboardHeightActivity.adjustKeyboardHeightKey);
|
||||
adjustKeyboardHeight.setTitle(getString(R.string.adjust_keyboard_height));
|
||||
|
|
@ -106,6 +107,13 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
|
|||
Intent adjustKeyboardHeightIntent = new Intent(context, AdjustKeyboardHeightActivity.class);
|
||||
adjustKeyboardHeight.setIntent(adjustKeyboardHeightIntent);
|
||||
|
||||
adjustLongpressDelay = new Preference(context);
|
||||
adjustLongpressDelay.setKey(AdjustLongpressDelayActivity.adjustLongpressDelayKey);
|
||||
adjustLongpressDelay.setTitle(getString(R.string.adjust_longpress_delay));
|
||||
adjustLongpressDelay.setWidgetLayoutResource(R.layout.preference_duration_icon_layout);
|
||||
Intent adjustLongpressDelayIntent = new Intent(context, AdjustLongpressDelayActivity.class);
|
||||
adjustLongpressDelay.setIntent(adjustLongpressDelayIntent);
|
||||
|
||||
/* Spacebar Caption Preference */
|
||||
|
||||
spacebarTextPreference = new ListPreference(context);
|
||||
|
|
@ -188,8 +196,6 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
|
|||
sendCrashReportPreference.setSummaryOff(getString(R.string.show_send_crash_report_off));
|
||||
sendCrashReportPreference.setDefaultValue(true);
|
||||
|
||||
|
||||
|
||||
screen.addPreference(languagesPreference);
|
||||
screen.addPreference(installKeyboardOrDictionary);
|
||||
screen.addPreference(displayLanguagePreference);
|
||||
|
|
@ -197,6 +203,7 @@ public class KeymanSettingsFragment extends PreferenceFragmentCompat {
|
|||
screen.addPreference(setDefaultKeyboardPreference);
|
||||
|
||||
screen.addPreference(adjustKeyboardHeight);
|
||||
screen.addPreference(adjustLongpressDelay);
|
||||
screen.addPreference(spacebarTextPreference);
|
||||
|
||||
screen.addPreference(hapticFeedbackPreference);
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
updateActiveLexicalModel();
|
||||
|
||||
ImageView imageView = (ImageView) layout.findViewById(R.id.image1);
|
||||
imageView.setImageResource(R.drawable.ic_arrow_forward);
|
||||
imageView.setImageResource(R.drawable.ic_action_forward);
|
||||
layout.setEnabled(true);
|
||||
layout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
|
|
@ -198,7 +198,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
* textView = (TextView) layout.findViewById(R.id.text1);
|
||||
* textView.setText(getString(R.string.manage_dictionary));
|
||||
* imageView = (ImageView) layout.findViewById(R.id.image1);
|
||||
* imageView.setImageResource(R.drawable.ic_arrow_forward);
|
||||
* imageView.setImageResource(R.drawable.ic_action_forward);
|
||||
*/
|
||||
|
||||
listView.setAdapter(adapter);
|
||||
|
|
@ -292,6 +292,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +346,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
holder.text.setText(kbd.getResourceName());
|
||||
holder.img.setImageResource(R.drawable.ic_arrow_forward);
|
||||
holder.img.setImageResource(R.drawable.ic_action_forward);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ public final class LanguagesSettingsActivity extends AppCompatActivity {
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +203,7 @@ public final class LanguagesSettingsActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
holder.textLang.setText(data.name);
|
||||
holder.img.setImageResource(R.drawable.ic_arrow_forward);
|
||||
holder.img.setImageResource(R.drawable.ic_action_forward);
|
||||
|
||||
holder.textCount.setText(getContext().getResources().getQuantityString(R.plurals.keyboard_count, data.keyboards.size(), data.keyboards.size()));
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
checkSendCrashReport();
|
||||
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);
|
||||
});
|
||||
|
|
@ -471,7 +472,8 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
|
||||
@Override
|
||||
public void onKeyboardLoaded(KeyboardType keyboardType) {
|
||||
// Do nothing
|
||||
// Initialize keyboard options
|
||||
KMManager.sendOptionsToKeyboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -602,8 +604,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
if (resourceId > 0)
|
||||
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
|
||||
|
||||
Point size = new Point(0, 0);
|
||||
getWindowManager().getDefaultDisplay().getSize(size);
|
||||
Point size = KMManager.getWindowSize(context);
|
||||
int screenHeight = size.y;
|
||||
Log.d(TAG, "Main resizeTextView bannerHeight: " + bannerHeight);
|
||||
textView.setHeight(screenHeight - statusBarHeight - actionBarHeight - bannerHeight - keyboardHeight);
|
||||
|
|
@ -646,7 +647,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
final View textSizeController = inflater.inflate(R.layout.text_size_controller, null);
|
||||
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this);
|
||||
dialogBuilder.setIcon(R.drawable.ic_light_action_textsize);
|
||||
dialogBuilder.setTitle(String.format(getString(R.string.text_size), textSize));
|
||||
dialogBuilder.setTitle(getTextSizeString());
|
||||
dialogBuilder.setView(textSizeController);
|
||||
dialogBuilder.setPositiveButton(getString(R.string.label_ok), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
|
|
@ -677,7 +678,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
textSize = progress + minTextSize;
|
||||
textView.setTextSize((float) textSize);
|
||||
dialog.setTitle(String.format(getString(R.string.text_size), textSize));
|
||||
dialog.setTitle(getTextSizeString());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -702,6 +703,16 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine a localized string for "Text Size" plus Arabic numerals
|
||||
* @return String
|
||||
*/
|
||||
private String getTextSizeString() {
|
||||
// Instead of formatting the number, will truncate formatting and concat the actual textSize
|
||||
String label = getString(R.string.text_size).replace("%1$d", "");
|
||||
return label + KMString.format(" %d", textSize);
|
||||
}
|
||||
|
||||
private void showClearTextDialog() {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this);
|
||||
dialogBuilder.setIcon(R.drawable.ic_light_action_trash);
|
||||
|
|
@ -866,9 +877,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
|
|||
}
|
||||
|
||||
public static Drawable getActionBarDrawable(Context context) {
|
||||
Point size = new Point();
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
wm.getDefaultDisplay().getSize(size);
|
||||
Point size = KMManager.getWindowSize(context);
|
||||
int width = size.x;
|
||||
|
||||
TypedValue outValue = new TypedValue();
|
||||
|
|
|
|||
|
|
@ -112,7 +112,8 @@ public class PackageActivity extends AppCompatActivity implements
|
|||
|
||||
// Number of languages associated with the first keyboard in a keyboard package.
|
||||
// lexical-model packages will be 0
|
||||
final int languageCount = kmpProcessor.getLanguageCount(pkgInfo, PackageProcessor.PP_KEYBOARDS_KEY, 0);
|
||||
final int languageCount = (keyboardCount > 0) ?
|
||||
kmpProcessor.getLanguageCount(pkgInfo, PackageProcessor.PP_KEYBOARDS_KEY, 0) : 0;
|
||||
|
||||
// Sanity check for keyboard packages
|
||||
if (pkgTarget.equals(PackageProcessor.PP_TARGET_KEYBOARDS)) {
|
||||
|
|
@ -180,6 +181,7 @@ public class PackageActivity extends AppCompatActivity implements
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
overridePendingTransition(0, android.R.anim.fade_out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public final class SelectPackageActivity extends AppCompatActivity {
|
|||
HashMap<String, String> hashMap = new HashMap<>();
|
||||
hashMap.put(titleKey, keyboardName);
|
||||
hashMap.put(subtitleKey, pkgID);
|
||||
String icon = String.valueOf(R.drawable.ic_arrow_forward);
|
||||
String icon = String.valueOf(R.drawable.ic_action_forward);
|
||||
hashMap.put(iconKey, icon);
|
||||
list.add(hashMap);
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 214 B |
|
Before Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 180 B |
|
After Width: | Height: | Size: 326 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
<item>
|
||||
<bitmap
|
||||
android:src="@drawable/sil_logo_blue_2017_1"
|
||||
android:src="@drawable/sil_logo_color_tai_heritage_pro"
|
||||
android:gravity="center"/>
|
||||
</item>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_navigation_back"
|
||||
android:tint="@color/keyman_blue" />
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_light_dialog_textsize_down"
|
||||
android:tint="@android:color/black"
|
||||
android:autoMirrored="true" />
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_light_dialog_textsize_up"
|
||||
android:tint="@android:color/black"
|
||||
android:autoMirrored="true"/>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M16.24,7.76C15.07,6.59 13.54,6 12,6v6l-4.24,4.24c2.34,2.34 6.14,2.34 8.49,0 2.34,-2.34 2.34,-6.14 -0.01,-8.48zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M0.99,19h2.42l1.27,-3.58h5.65L11.59,19h2.42L8.75,5h-2.5L0.99,19zM5.41,13.39L7.44,7.6h0.12l2.03,5.79H5.41zM23,11v2h-8v-2H23z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="48dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M0.99,19h2.42l1.27,-3.58h5.65L11.59,19h2.42L8.75,5h-2.5L0.99,19zM5.41,13.39L7.44,7.6h0.12l2.03,5.79H5.41zM20,11h3v2h-3v3h-2v-3h-3v-2h3V8h2V11z"/>
|
||||
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<include layout="@layout/titlebar" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="25dp"
|
||||
android:paddingTop="60dp" >
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/delayTimeDownButton"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/ic_delay_time_down"
|
||||
android:src="@drawable/ic_action_decrement" />
|
||||
|
||||
<!-- Seekbar range 0 to 6 corresponds to longpress duration 300 ms to 1500 ms -->
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar"
|
||||
android:layout_width="180dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/ic_longpress_delay_slider"
|
||||
android:progress="1"
|
||||
android:max="6"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/delayTimeUpButton"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/ic_delay_time_up"
|
||||
android:src="@drawable/ic_action_increment" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/delayTimeText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/linearLayout"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginStart="@dimen/activity_horizontal_margin"
|
||||
android:text="@string/longpress_delay_time"
|
||||
android:textSize="@dimen/longpress_delay_label_textsize"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/ms_white"
|
||||
tools:context=".InfoActivity" >
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/ms_white"
|
||||
tools:context=".InfoActivity" >
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/titlebar"
|
||||
|
|
@ -15,24 +15,31 @@
|
|||
android:layout_alignParentTop="true"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
|
||||
|
||||
<!-- Navigation buttons -->
|
||||
<ImageButton
|
||||
android:id="@+id/back_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:contentDescription="@string/label_back"
|
||||
android:src="@drawable/ic_navigation_back" />
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forward_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/label_forward"
|
||||
android:src="@drawable/ic_navigation_forward" />
|
||||
<!-- Navigation buttons in a LinearLayout to mirror on RTL -->
|
||||
<ImageButton
|
||||
android:id="@+id/back_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:contentDescription="@string/label_back"
|
||||
android:src="@drawable/ic_action_back" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forward_button"
|
||||
style="?android:attr/actionButtonStyle"
|
||||
app:tint="@color/image_button_color"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/label_forward"
|
||||
android:src="@drawable/ic_action_forward" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/close_button"
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/image_button"
|
||||
android:src="@drawable/ic_navigation_back" />
|
||||
android:src="@drawable/ic_action_back" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forwardButton"
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/image_button"
|
||||
android:src="@drawable/ic_navigation_forward" />
|
||||
android:src="@drawable/ic_action_forward" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/bookmarksButton"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="@dimen/preference_icon"
|
||||
android:layout_height="@dimen/preference_icon"
|
||||
android:src="@drawable/ic_action_timelapse" />
|
||||
|
|
@ -2,4 +2,4 @@
|
|||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="@dimen/preference_icon"
|
||||
android:layout_height="@dimen/preference_icon"
|
||||
android:src="@drawable/ic_arrow_forward" />
|
||||
android:src="@drawable/ic_action_forward" />
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/ic_text_size_down"
|
||||
android:src="@drawable/ic_light_dialog_textsize_down" />
|
||||
android:src="@drawable/textsize_decrease" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekBar"
|
||||
|
|
@ -32,6 +32,6 @@
|
|||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/ic_text_size_up"
|
||||
android:src="@drawable/ic_light_dialog_textsize_up" />
|
||||
android:src="@drawable/textsize_increase" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_margin="3dp"
|
||||
android:padding="4dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_above="@+id/progressBar"
|
||||
android:weightSum="2"
|
||||
|
|
@ -76,7 +75,6 @@
|
|||
style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/keyman_bar_height"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:visibility="visible"
|
||||
|
|
|
|||
168
android/KMAPro/kMAPro/src/main/res/values-ar-rSA/strings.xml
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- app_name removed in 16.0 beta. Set in build.gradle -->
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_share" comment="Menu action to send text content to another app">مشاركة</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_web" comment="Menu action to open Keyman browser">متصفح ويب</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_text_size" comment="Menu action to adjust text size">حجم النص</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_overflow" comment="Show additional menu items">المزيد</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_clear_text" comment="Menu action to erase text">محو النص</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_info" comment="Menu action to display Keyman help page">معلومات</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_settings" comment="Menu action to open Settings menu">الإعدادات</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_install_updates" comment="Menu notification that keyboard or dictionary updates available">تنزيل التحديثات</string>
|
||||
<!-- Context: Title -->
|
||||
<string name="title_version" comment="Title of Keyman for Android version">إصدار: %1$s</string>
|
||||
<!-- Context: Text label when old Chrome version installed -->
|
||||
<string name="text_require_chrome_57" comment="Banner text when old version of Chrome is installed">يتطلب Keyman إصدار 57 من Chrome أو أعلى.</string>
|
||||
<!-- Context: Button label -->
|
||||
<string name="button_update_chrome" comment="Prompt to upgrade Chrome in the Play Store">تحديث Chrome</string>
|
||||
<!-- Context: Textfield prompt (… is the ellipsis character "...") -->
|
||||
<string name="textview_hint" comment="Prompt to start typing">ابدأ الكتابة هنا…</string>
|
||||
<!-- Context: Splash screen (version/copyright info currently disabled -->
|
||||
<!-- Context: Splash screen (version/copyright info currently disabled -->
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="text_size" comment="Current text size (number)">حجم النص: %1$d</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_up" comment="Make text bigger">تكبير حجم النص</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_down" comment="Make text smaller">تصغير حجم النص</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Text size slider</string>
|
||||
<!-- Context: Clear Text dialog -->
|
||||
<string name="all_text_will_be_cleared" comment="Erase all the text">\nسيتم محو كل النص\n</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="get_started" comment="Menu for getting started">إبدأ الآن</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="add_a_keyboard" comment="Menu item to add a keyboard">اضف لوحة مفاتيح بلغتك</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="enable_system_keyboard" comment="Menu item to enable Keyman as system keyboard">تمكين Keyman لوحة المفاتيح الأساسية للنظام</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="set_keyman_as_default" comment="Menu item to set Keyman as default system keyboard">إعداد Keyman لوحة المفاتيح الإفتراضية</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="more_info" comment="Open the Keyman for Android help page">المزيد من المعلومات</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="show_get_started" comment="Show the "Get Started" menu on startup">أظهر \"%1$s\" عند البدء</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages">لتثبيت حزم لوحات المفاتيح، امنح Keyman الإذن لقراءة التخزين الخارجي.</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted">تم رفض أذونات التخزين. قد يفشل تثبيت حزمة لوحة المفاتيح</string>
|
||||
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file"> Storage permission request failed. Try Keyman Settings - Install from local file</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="keyman_settings" comment="Settings menu title">الإعدادات</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<plurals name="installed_languages">
|
||||
<item quantity="zero">اللغات المثبتة (%1$d)</item>
|
||||
<item quantity="one">اللغات المثبتة (%1$d)</item>
|
||||
<item quantity="two">اللغات المثبتة (%1$d)</item>
|
||||
<item quantity="few">اللغات المثبتة (%1$d)</item>
|
||||
<item quantity="many">اللغات المثبتة (%1$d)</item>
|
||||
<item quantity="other">اللغات المثبتة (%1$d)</item>
|
||||
</plurals>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="install_keyboard_or_dictionary" comment="Menu item to install keyboard or dictionary">تثبيت لوحة المفاتيح او القاموس</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="change_display_language" comment="Menu action to change interface language">لغة العرض</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">تعديل ارتفاع لوحة المفاتيح</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">نص مفتاح المسافة</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_keyboard" comment="Spacebar caption option - keyboard">لوحة المفاتيح</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_language" comment="Spacebar caption option - language">اللغة</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_language_keyboard" comment="Spacebar caption option - language + keyboard">اللغة + لوحة المفاتيح</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_blank" comment="Spacebar caption option - blank">فارغ</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_keyboard" comment="Spacebar caption hint - keyboard">أظهر اسم لوحة المفاتيح على مفتاح المسافة</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_language" comment="Spacebar caption hint - language">أظهر اسم اللغة على المسافة</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_language_keyboard" comment="Spacebar caption hint - language + keyboard">اللغة ولوحة المفاتيح على المسافة</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">لا تظهر نص على المسافة</string>
|
||||
<!-- Context: Keyman Settings menu / Haptic feedback -->
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">الاهتزاز عند الكتابة</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner" comment="text suggestions banner">إظهار اللافتة دائماً</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner_on" comment="Description when toggle is on">سيتم تنفيذها</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner_off" comment="Description when toggle is off">عند إيقاف التشغيل، يظهر فقط عند تفعيل النص التنبؤي</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_send_crash_report" comment="permission for sending crash reports">السماح بإرسال تقارير توقف التشغيل المفاجئ عبر الشبك</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_send_crash_report_on" comment="Description when toggle is on">عند التشغيل، سيتم إرسال تقارير التوقف المفاجئ</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_send_crash_report_off" comment="Description when toggle is off">عند إيقاف التشغيل، لن يتم إرسال التقارير</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="install_from_keyman_dot_com" comment="Install package from Keyman server">تثبيت من keyman.com</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="install_from_local_file" comment="Install package file from local device">التثبيت من ملف محلي</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="install_from_other_device" comment="Scan QR Code">التثبيت من جهاز آخر</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="add_languages_to_installed_keyboard" comment="Install additional languages from a keyboard package">اضف لغات للوحة المفاتيح المثبتة</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="add_language_subtext" comment="Additional information for adding another language">(من حزمة لوحة المفاتيح)</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="title_select_keyboard_package_list" comment="Select a keyboard package to add languages">اختر حزمة لوحة مفاتيح</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="title_select_languages_for_package" comment="Select language names from the keyboard package">اختر لغة %1$s</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="added_language_to_keyboard" comment="Notification that a language name is added to a keyboard">تمت اضافة %1$s إلى %2$s</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">كل اللغات مثبتة مسبقا</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">اسحب لوحة المفاتيح لتغيير مدى ارتفاعها</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">دور الجهاز لضبط الوضع العمودي والوضع الأفقي</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="reset_to_defaults" comment="Button to reset to default heights">إعادة ضبط الافتراضيات</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_text" comment="Prompt to type in the browser search bar">ابحث أو اكتب عنوان URL</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="title_bookmarks" comment="Title for bookmarks">علامات مرجعية</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="no_bookmarks" comment="Text when bookmark list is empty">لا تتوفر أي علامات مرجعية</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="add_bookmark" comment="Confirmation to add bookmark">أضف علامة مرجعية</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_title" comment="Page title for saved bookmark">العنوان</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_url" comment="Page URL for saved bookmark">عنوان Url</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="title_package_failed_to_install" comment="Error dialog title when package failed to install">فشل في تنزيل حزمة %1$s</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="downloading_keyboard_package" comment="Confirmation to download keyboard package filename">يتم الآن تحميل لوحة مفاتيح حزمة \n%1$s…</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="failed_to_extract" comment="Notification that keyboard package failed to unzip">فشل في الإستخراج</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="install_keyboard_package" comment="Title to install keyboard package">تثبيت لوحة المفاتيح</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="install_predictive_text_package" comment="Title to install dictionary package">تثبيت القاموس</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="not_valid_package_file" comment="Notification when invalid package file cannot be installed">ليس %1$s ملف حزمة صالحة لبرنامج Keyman.\n%2$s\"</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_new_touch_keyboards_to_install" comment="Notification when no touch-optimized keyboards can be installed">ليس في حزمة لوحة المفاتيح لوحات مفاتيح مكيّفة لشاشات اللمس</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_new_predictive_text_to_install" comment="Notification when no dictionaries can be installed">لا يوجد نصوص تنبؤية للتنزيل</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_targets_to_install" comment="Notification when a package doesn't contain keyboards or dictionaries">لا لوحات مفاتيح و نصوص تنبؤية للتنزيل</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_associated_languages" comment="Notification when a keyboard package doesn't contain languages">ليس لحزمة لوحة المفاتيح لغات ذات صلة لتثبيتها</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">غير صالح\ناقص البيانات الوصفية في الحزمة</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman">تتطلب لوحة المفاتيح إصدارًا أحدث من Keyman</string>
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">غير قادر على تشغيل متصفح الويب</string>
|
||||
</resources>
|
||||
164
android/KMAPro/kMAPro/src/main/res/values-b+el/strings.xml
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- app_name removed in 16.0 beta. Set in build.gradle -->
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_share" comment="Menu action to send text content to another app">Μοιρασθῆτε</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_web" comment="Menu action to open Keyman browser">Φυλλομετρητής</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_text_size" comment="Menu action to adjust text size">Μέγεθος κειμένου</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_overflow" comment="Show additional menu items">Περισσότερα</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_clear_text" comment="Menu action to erase text">Διαγραφὴ κειμένου</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_info" comment="Menu action to display Keyman help page">Πληροφορίες</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_settings" comment="Menu action to open Settings menu">Ρυθμίσεις</string>
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_install_updates" comment="Menu notification that keyboard or dictionary updates available">Εγκατάσταση Ενημερώσεων</string>
|
||||
<!-- Context: Title -->
|
||||
<string name="title_version" comment="Title of Keyman for Android version">Ἔκδοση %1$s</string>
|
||||
<!-- Context: Text label when old Chrome version installed -->
|
||||
<string name="text_require_chrome_57" comment="Banner text when old version of Chrome is installed">Τὸ Keyman ἀπαιτεῖ ἔκδοση Chrome 57 ἢ νεώτερη.</string>
|
||||
<!-- Context: Button label -->
|
||||
<string name="button_update_chrome" comment="Prompt to upgrade Chrome in the Play Store">Ἐνημερῶστε τὸ Chrome</string>
|
||||
<!-- Context: Textfield prompt (… is the ellipsis character "...") -->
|
||||
<string name="textview_hint" comment="Prompt to start typing">Ἀρχίστε νὰ γράφετε ἐδῶ…</string>
|
||||
<!-- Context: Splash screen (version/copyright info currently disabled -->
|
||||
<!-- Context: Splash screen (version/copyright info currently disabled -->
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="text_size" comment="Current text size (number)">Μέγεθος κειμένου: %1$d</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_up" comment="Make text bigger">Μεγαλῶστε τὴν γραμματοσειρά</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_down" comment="Make text smaller">Μικρύνετε τὴν γραμματοσειρά</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Ρύθμιση μεγέθους κειμένου</string>
|
||||
<!-- Context: Clear Text dialog -->
|
||||
<string name="all_text_will_be_cleared" comment="Erase all the text">\nΤὸ κείμενο θὰ ἐκκαθαρισθεῖ πλήρως\n</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="get_started" comment="Menu for getting started">Μικρύνετε τὸ κείμενο</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="add_a_keyboard" comment="Menu item to add a keyboard">Προσθέστε πληκτρολόγιο γιὰ τὴν γλῶσσα σας</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="enable_system_keyboard" comment="Menu item to enable Keyman as system keyboard">Ὁρίστε τὸ Κῆμαν ὡς παν-συστημικὸ πληκτρολόγιο</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="set_keyman_as_default" comment="Menu item to set Keyman as default system keyboard">Ὁρίστε τὸ Κῆμαν ὡς προεπιλεγμένο πληκτρολόγιο</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="more_info" comment="Open the Keyman for Android help page">Περισσότερες πληροφορίες</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
<string name="show_get_started" comment="Show the "Get Started" menu on startup">Κατὰ τὴν ἔναρξη νὰ προβάλλεται τὸ \"%1$s</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages">Γιὰ νὰ ἐγκαταστήσετε πακέτα πληκτρολογίων, ἐπιτρέψτε στὸ Κῆμαν νὰ διαβάζει ἐξωτερικὸ χῶρο ἀποθήκευσης.</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted">Ἀπερρίφθη αἴτημα χώρου ἀποθήκευσης. Πιθανὴ ἀποτυχία ἐγκατάστασης πακέτου πληκτρολογίου</string>
|
||||
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file">Ἀπερρίφθη αἴτημα χώρου ἀποθηκεύσεως. Δοκιμάστε τὶς ρυθμίσεις Κῆμαν - Ἐγκατάσταση ἀπὸ τοπικὸ ἀρχεῖο</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="keyman_settings" comment="Settings menu title">Ρυθμίσεις</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<plurals name="installed_languages">
|
||||
<item quantity="one">Ἐγκατεστημένες γλῶσσες (%1$d)</item>
|
||||
<item quantity="other">Ἐγκατεστημένες γλῶσσες (%1$d)</item>
|
||||
</plurals>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="install_keyboard_or_dictionary" comment="Menu item to install keyboard or dictionary">Ἐγκαταστῆστε πληκτρολόγιο ἢ λεξικό</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="change_display_language" comment="Menu action to change interface language">Γλῶσσα προβολῆς</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Μεταβολὴ ὕψους πληκτρολογίου</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">Λεζάντα πλήκτρου διαστήματος</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_keyboard" comment="Spacebar caption option - keyboard">Πληκτρολόγιο</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_language" comment="Spacebar caption option - language">Γλῶσσα</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_language_keyboard" comment="Spacebar caption option - language + keyboard">Γλῶσσα + Πληκτρολόγιο</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_blank" comment="Spacebar caption option - blank">Κενό</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_keyboard" comment="Spacebar caption hint - keyboard">\'Ονομα πληκτρολογίου στὸ πλῆκτρο διαστήματος</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_language" comment="Spacebar caption hint - language">Ὄνομα γλώσσας στὸ πλῆκτρο διαστήματος</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_language_keyboard" comment="Spacebar caption hint - language + keyboard">Ὄνομα πληκτρολογίου καὶ γλώσσας στὸ πλῆκτρο διαστήματος</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Καμμία λεζάντα στὸ πλῆκτρο διαστήματος</string>
|
||||
<!-- Context: Keyman Settings menu / Haptic feedback -->
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Δὸνηση κατὰ τὴν πληκτρολόγηση</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner" comment="text suggestions banner">Νὰ ἐμφανίζεται πάντα banner</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner_on" comment="Description when toggle is on">Πρὸς ὑλοποίησιν</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner_off" comment="Description when toggle is off">OFF: ἐμφάνιση μόνον ὅταν ἔχει ἐνεργοποιηθεῖ ἡ πρόβλεψη κειμένου</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_send_crash_report" comment="permission for sending crash reports">Ἐπιτρέψτε τὴν ἀποστολὴ ἀναφορῶν κατάρρευσης μέσῳ δικτύου</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_send_crash_report_on" comment="Description when toggle is on">ON: Ἀποστολὴ ἀναφορῶν κατάρρευσης</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_send_crash_report_off" comment="Description when toggle is off">OFF: Δὲν ἀποστέλλονται ἀναφορὲς κατάρρευσης</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="install_from_keyman_dot_com" comment="Install package from Keyman server">Ἐγκατάσταση ἀπὸ τὸ keyman.com</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="install_from_local_file" comment="Install package file from local device">Ἐγκατάσταση ἀπὸ τοπικὸ ἀρχεῖο</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="install_from_other_device" comment="Scan QR Code">Ἐγκατάσταση ἀπὸ ἄλλη συσκευή</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="add_languages_to_installed_keyboard" comment="Install additional languages from a keyboard package">Προσθέστε γλῶσσες σὲ ἐγκατεστημένο πληκτρολόγιο</string>
|
||||
<!-- Context: Keyman Settings "Install Keyboard or Dictionary" menu -->
|
||||
<string name="add_language_subtext" comment="Additional information for adding another language">(ἀπὸ πακέτο πληκτρολογίου)</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="title_select_keyboard_package_list" comment="Select a keyboard package to add languages">Ἐπιλέξτε Πακέτο Πληκτρολογίου</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="title_select_languages_for_package" comment="Select language names from the keyboard package">Ἐπιλέξτε γλῶσσες γιὰ τὸ %1$s</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="added_language_to_keyboard" comment="Notification that a language name is added to a keyboard">Προσετέθη ἡ γλῶσσα %1$s στὸ %2$s</string>
|
||||
<!-- Context: Select Package and Select Languages menu -->
|
||||
<string name="all_languages_installed" comment="Text when all languages from a keyboard package have been installed">Ὅλες οἱ γλῶσσες ἔχουν ἤδη ἐγκατασταθεῖ</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="drag_the_keyboard" comment="First line of adjusting keyboard height">Σύρετε τὸ πληκτρολόγιο γιὰ νὰ ἀλλάξετε τὸ ὕψος του</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Περιστρέψτε τὴν συσκευὴ γιὰ προσαρμογὴ τοῦ ὕψους σὲ λειτουργία πορτραίτου καὶ τοπίου</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="reset_to_defaults" comment="Button to reset to default heights">Ἐπαναφέρετε τὶς προεπιλεγμένες ρυθμίσεις</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_text" comment="Prompt to type in the browser search bar">Ἀναζητῆστε ἢ πληκτρολογῆστε URL</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="title_bookmarks" comment="Title for bookmarks">Σελιδοδεῖκτες</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="no_bookmarks" comment="Text when bookmark list is empty">Δὲν ὑπάρχουν σελιδοδεῖκτες</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="add_bookmark" comment="Confirmation to add bookmark">Προσθέστε σελιδοδείκτη</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_title" comment="Page title for saved bookmark">Τίτλος</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_url" comment="Page URL for saved bookmark">URL</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="title_package_failed_to_install" comment="Error dialog title when package failed to install">Τὸ πακέτο %1$s ἀπέτυχε νὰ ἐγκατασταθεῖ</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="downloading_keyboard_package" comment="Confirmation to download keyboard package filename">Λήψη πακέτου πληκτρολογίου\n%1$s…</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="failed_to_extract" comment="Notification that keyboard package failed to unzip">Ἀποτυχία ἐξαγωγῆς</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="install_keyboard_package" comment="Title to install keyboard package">Ἐγκαταστῆστε πληκτρολόγιο</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="install_predictive_text_package" comment="Title to install dictionary package">Ἐγκαταστῆστε Λεξικό</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="not_valid_package_file" comment="Notification when invalid package file cannot be installed">Τὸ %1$s δὲν εἶναι ἔγκυρο ἀρχεῖο πακέτου Κῆμαν.\n%2$s\"</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_new_touch_keyboards_to_install" comment="Notification when no touch-optimized keyboards can be installed">Τὸ πακέτο πληκτρολογίου δὲν ἔχει βελτιστοποιημένα πληκτρολόγια ἀφῆς πρὸς ἐγκατάστασιν</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_new_predictive_text_to_install" comment="Notification when no dictionaries can be installed">Δὲν ὑπάρχουν προγνώσεις κειμένων πρὸς ἐγκατάστασιν</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_targets_to_install" comment="Notification when a package doesn't contain keyboards or dictionaries">Δὲν ὑπάρχουν πληκτρολόγια ἢ προγνώσεις κειμένων πρὸς ἐγκατάστασιν</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="no_associated_languages" comment="Notification when a keyboard package doesn't contain languages">Τὸ πακέτο πληκτρολογίου δὲν ἔχει σχετικὲς μὲ αὐτὸ γλῶσσες πρὸς ἐγκατάστασιν</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">Ἄκυρα/ἐλλιπῆ μεταδεδομένα στὸ πακέτο</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> Τὸ πληκτρολόγιο ἀπαιτεῖ νεώτερη ἔκδοση τοῦ Κῆμαν</string>
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Ἀδυναμία ἐκκινήσεως φυλλομετρητῆ</string>
|
||||
</resources>
|
||||
|
|
@ -33,6 +33,8 @@
|
|||
<string name="ic_text_size_up" comment="Make text bigger">Velikost textu nahoru</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_down" comment="Make text smaller">Velikost textu dolů</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Posuvník velikosti textu</string>
|
||||
<!-- Context: Clear Text dialog -->
|
||||
<string name="all_text_will_be_cleared" comment="Erase all the text">\nVeškerý text bude vymazán\n</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
|
|
@ -51,6 +53,7 @@
|
|||
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages"> Pro instalaci balíčků klávesnice povolte klávesnici oprávnění ke čtení externího úložiště.</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted"> Žádost o oprávnění k úložišti byla zamítnuta. Může selhat instalace balíčku klávesnice</string>
|
||||
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file"> Žádost o oprávnění k úložišti se nezdařila. Zkuste nastavení Keyman - Instalovat z místního souboru</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="keyman_settings" comment="Settings menu title">Nastavení</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -67,6 +70,8 @@
|
|||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Upravit výšku klávesnice</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_longpress_delay" comment="Menu action to adjust longpress delay duration">Upravit zpoždění dlouhého stisknutí</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">Titulek mezerníku</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_keyboard" comment="Spacebar caption option - keyboard">Keyboard</string>
|
||||
|
|
@ -85,7 +90,7 @@
|
|||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Nezobrazovat titulek v mezerníku</string>
|
||||
<!-- Context: Keyman Settings menu / Haptic feedback -->
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Vibrate when typing</string>
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Při psaní vibrovat</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner" comment="text suggestions banner">Vždy zobrazovat banner</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -122,6 +127,14 @@
|
|||
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Otočit zařízení pro nastavení na výšku a na šířku</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="reset_to_defaults" comment="Button to reset to default heights">Obnovit výchozí nastavení</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="longpress_delay_time" comment="Current longpress delay time (seconds)">Doba zpoždění: %1$.1f sekund</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_up" comment="Make longpress delay longer">Prodloužit dobu zpoždění</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_down" comment="Make longpress delay shorter">Zkrátit dobu zpoždění</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_longpress_delay_slider" comment="Adjust longpress delay time">Posuvník doby zpoždění dlouhého stisknutí</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_text" comment="Prompt to type in the browser search bar">Hledat nebo zadat URL</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
|
|
@ -157,7 +170,7 @@
|
|||
<!-- Context: KMP Package strings -->
|
||||
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">Neplatná/chybějící metadata v balíčku</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> Keyboard requires a newer version of Keyman</string>
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> Klávesnice vyžaduje novější verzi Keyman</string>
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Unable to launch web browser</string>
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Nelze spustit webový prohlížeč</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_down" comment="Make text smaller">Text kleiner</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Text size slider</string>
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Slider für Textgröße</string>
|
||||
<!-- Context: Clear Text dialog -->
|
||||
<string name="all_text_will_be_cleared" comment="Erase all the text">\nDer gesamte Text wird gelöscht\n</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
|
|
@ -53,6 +53,7 @@
|
|||
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages"> Um Tastaturpakete zu installieren, braucht Keyman die Berechtigung zum Lesen von externem Speicher.</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted"> Zugriff auf den Speicher wurde abgelehnt. Möglicherweise funktioniert die Installation des Tastaturpakets nicht korrekt</string>
|
||||
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file"> Speicherberechtigungsanfrage fehlgeschlagen. Versuchen Sie die Keyman Einstellungen - Aus der lokalen Datei installieren</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="keyman_settings" comment="Settings menu title">Einstellungen</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -63,7 +64,7 @@
|
|||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="install_keyboard_or_dictionary" comment="Menu item to install keyboard or dictionary">Tastatur oder Wörterbuch installieren</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="change_display_language" comment="Menu action to change interface language">Sprache anzeigen</string>
|
||||
<string name="change_display_language" comment="Menu action to change interface language">Anzeigesprache</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Tastaturhöhe anpassen</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- app_name removed in 16.0 beta. Set in build.gradle -->
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_share" comment="Menu action to send text content to another app">Condividi</string>
|
||||
<!-- Context: Menu Action -->
|
||||
|
|
@ -32,6 +33,8 @@
|
|||
<string name="ic_text_size_up" comment="Make text bigger">Dimensione testo in alto</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_down" comment="Make text smaller">Dimensione del testo giù</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Cursore dimensione testo</string>
|
||||
<!-- Context: Clear Text dialog -->
|
||||
<string name="all_text_will_be_cleared" comment="Erase all the text">\nTutto il testo sarà cancellato\n</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
|
|
@ -50,6 +53,7 @@
|
|||
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages"> Per installare pacchetti di tastiera, consentire a Keyman di leggere la memoria esterna.</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted"> La richiesta di autorizzazione all\'archiviazione è stata negata. Potrebbe non essere stato possibile installare il pacchetto tastiera</string>
|
||||
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file"> Richiesta di autorizzazione archiviazione non riuscita. Prova Impostazioni Keyman - Installa da file locale</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="keyman_settings" comment="Settings menu title">Impostazioni</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -64,6 +68,8 @@
|
|||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Regola altezza tastiera</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_longpress_delay" comment="Menu action to adjust longpress delay duration">Adjust longpress delay</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">Didascalia barra spaziatrice</string>
|
||||
<!-- Context: Keyman Settings menu / Spacebar caption -->
|
||||
<string name="spacebar_caption_keyboard" comment="Spacebar caption option - keyboard">Keyboard</string>
|
||||
|
|
@ -82,7 +88,7 @@
|
|||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Non mostrare la didascalia sulla barra spaziatrice</string>
|
||||
<!-- Context: Keyman Settings menu / Haptic feedback -->
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Vibrate when typing</string>
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Vibra durante la digitazione</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner" comment="text suggestions banner">Mostra sempre il banner</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -119,6 +125,14 @@
|
|||
<string name="rotate_the_device" comment="Second line of adjusting keyboard height">Ruota il dispositivo per regolare verticale e orizzontale</string>
|
||||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="reset_to_defaults" comment="Button to reset to default heights">Ripristina impostazioni predefinite</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="longpress_delay_time" comment="Current longpress delay time (seconds)">Delay Time: %1$.1f seconds</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_up" comment="Make longpress delay longer">Delay time longer</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_down" comment="Make longpress delay shorter">Delay time shorter</string>
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_longpress_delay_slider" comment="Adjust longpress delay time">Longpress delay time slider</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_text" comment="Prompt to type in the browser search bar">Cerca o digita URL</string>
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
|
|
@ -154,7 +168,7 @@
|
|||
<!-- Context: KMP Package strings -->
|
||||
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">Metadati non validi/mancanti nel pacchetto</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> Keyboard requires a newer version of Keyman</string>
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> La tastiera richiede una nuova versione di Keyman</string>
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Unable to launch web browser</string>
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Impossibile avviare il browser web</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- app_name removed in 16.0 beta. Set in build.gradle -->
|
||||
<!-- Context: Menu Action -->
|
||||
<string name="action_share" comment="Menu action to send text content to another app">Compartilhar</string>
|
||||
<!-- Context: Menu Action -->
|
||||
|
|
@ -32,6 +33,8 @@
|
|||
<string name="ic_text_size_up" comment="Make text bigger">Tamanho do texto para cima</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_down" comment="Make text smaller">Tamanho do texto para baixo</string>
|
||||
<!-- Context: Text Size dialog -->
|
||||
<string name="ic_text_size_slider" comment="Adjust text size">Tamanho do texto deslizante</string>
|
||||
<!-- Context: Clear Text dialog -->
|
||||
<string name="all_text_will_be_cleared" comment="Erase all the text">\nTodo o texto será limpo\n</string>
|
||||
<!-- Context: Get Started menu -->
|
||||
|
|
@ -50,6 +53,7 @@
|
|||
<string name="request_storage_permission" comment="Request storage permission to access keyboard packages"> Para instalar pacotes de teclado, permita que o Keyman leia o armazenamento externo.</string>
|
||||
<!-- Context: Android Storage Permission -->
|
||||
<string name="storage_permission_denied" comment="Keyboard package installation may fail since Android storage permission not granted"> A solicitação de permissão de armazenamento foi negada. Pode falhar na instalação do pacote de teclado</string>
|
||||
<string name="storage_permission_denied2" comment="Keyboard package installation failed. Recommend install from local file"> Falha no pedido de permissão de armazenamento. Experimente instalar de um ficheiro local, nas configurações do Keyman</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="keyman_settings" comment="Settings menu title">Configurações</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -82,7 +86,7 @@
|
|||
<!-- Context: Keyman Settings menu / Spacebar caption hint -->
|
||||
<string name="spacebar_caption_hint_blank" comment="Spacebar caption hint - blank">Não mostrar legenda na barra de espaço</string>
|
||||
<!-- Context: Keyman Settings menu / Haptic feedback -->
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Vibrate when typing</string>
|
||||
<string name="haptic_feedback" comment="haptic feedback on key press">Vibrar ao tocar</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="show_banner" comment="text suggestions banner">Sempre mostrar banner</string>
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
|
|
@ -154,7 +158,7 @@
|
|||
<!-- Context: KMP Package strings -->
|
||||
<string name="invalid_metadata" comment="kmp.json metadata file is invalid or missing in package">Metadados inválidos/ausentes no pacote</string>
|
||||
<!-- Context: KMP Package strings -->
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman"> Keyboard requires a newer version of Keyman</string>
|
||||
<string name="minimum_keyboard_version_not_supported" comment="Notification when keyboard has functionality not supported by current Keyman">O teclado requer uma nova versão do Keyman</string>
|
||||
<!-- Context: anywhere -->
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Unable to launch web browser</string>
|
||||
<string name="unable_to_open_browser" comment="Notification when a browser activity cannot be launched">Não foi possível carregar o navegador</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -23,4 +23,5 @@
|
|||
<dimen name="preference_icon">32dp</dimen>
|
||||
<dimen name="update_indicator_size">16dp</dimen>
|
||||
<dimen name="update_indicator_bg_margin">0dp</dimen>
|
||||
<dimen name="longpress_delay_label_textsize">24sp</dimen>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@
|
|||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_keyboard_height" comment="Menu action to adjust keyboard height">Adjust keyboard height</string>
|
||||
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="adjust_longpress_delay" comment="Menu action to adjust longpress delay duration">Adjust longpress delay</string>
|
||||
|
||||
<!-- Context: Keyman Settings menu -->
|
||||
<string name="spacebar_caption" comment="Menu action to set the spacebar caption">Spacebar caption</string>
|
||||
|
||||
|
|
@ -198,6 +201,17 @@
|
|||
<!-- Context: Adjust Keyboard Height menu -->
|
||||
<string name="reset_to_defaults" comment="Button to reset to default heights">Reset to Defaults</string>
|
||||
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="longpress_delay_time" comment="Current longpress delay time (seconds)">Delay Time: %1$.1f seconds</string>
|
||||
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_up" comment="Make longpress delay longer">Delay time longer</string>
|
||||
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_delay_time_down" comment="Make longpress delay shorter">Delay time shorter</string>
|
||||
|
||||
<!-- Context: Adjust Longpress Delay Time menu -->
|
||||
<string name="ic_longpress_delay_slider" comment="Adjust longpress delay time">Longpress delay time slider</string>
|
||||
|
||||
<!-- Context: Keyman Web Browser -->
|
||||
<string name="hint_text" comment="Prompt to type in the browser search bar">Search or type URL</string>
|
||||
|
|
|
|||
|
|
@ -55,17 +55,17 @@ android {
|
|||
|
||||
dependencies {
|
||||
// 1.6.0-rc01 needed to resolve https://issuetracker.google.com/issues/238425626
|
||||
implementation 'androidx.appcompat:appcompat:1.6.0-rc01' // 1.5.1
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
// material:1.7.0 will need Gradle plugin 7.1.0+
|
||||
implementation 'com.google.android.material:material:1.6.0'
|
||||
implementation 'commons-io:commons-io:2.6'
|
||||
implementation 'io.sentry:sentry-android:6.9.2'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'commons-io:commons-io:2.13.0'
|
||||
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.4'
|
||||
testImplementation 'org.robolectric:robolectric:4.8.1'
|
||||
testImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
testImplementation 'org.robolectric:robolectric:4.10.3'
|
||||
|
||||
// Generate QR Codes
|
||||
implementation ('com.github.kenglxn.QRGen:android:3.0.1') {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ var bannerHeight = 0;
|
|||
var bannerImagePath = '';
|
||||
var bannerHTMLContents = '';
|
||||
var fragmentToggle = 0;
|
||||
var deferredBannerCall;
|
||||
|
||||
var sentryManager = new KeymanSentryManager({
|
||||
hostPlatform: "android"
|
||||
|
|
@ -49,6 +50,12 @@ function init() {
|
|||
|
||||
// The OSK is not available until initialization is complete.
|
||||
keyman.osk.bannerView.activeBannerHeight = bannerHeight;
|
||||
|
||||
if(deferredBannerCall) {
|
||||
deferredBannerCall();
|
||||
deferredBannerCall = null;
|
||||
}
|
||||
|
||||
keyman.refreshOskLayout();
|
||||
}
|
||||
});
|
||||
|
|
@ -63,10 +70,19 @@ function init() {
|
|||
}
|
||||
|
||||
function showBanner(flag) {
|
||||
if(!keyman.osk) {
|
||||
deferredBannerCall = function() {
|
||||
showBanner(flag);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var bc = keyman.osk.bannerController;
|
||||
|
||||
console_debug("Setting banner display for dictionaryless keyboards to " + flag);
|
||||
console_debug("bannerHTMLContents: " + bannerHTMLContents);
|
||||
var bc = keyman.osk.bannerController;
|
||||
if (bc) {
|
||||
if(bc) {
|
||||
if (bannerHTMLContents != '') {
|
||||
bc.inactiveBanner = flag ? new bc.HTMLBanner(bannerHTMLContents) : null;
|
||||
} else {
|
||||
|
|
@ -96,6 +112,17 @@ function notifyHost(event, params) {
|
|||
}, 10);
|
||||
}
|
||||
|
||||
// Update the KeymanWeb longpress delay
|
||||
// delay is in milliseconds
|
||||
function setLongpressDelay(delay) {
|
||||
if (keyman.osk) {
|
||||
keyman.osk.gestureParams.longpress.waitLength = delay;
|
||||
console_debug('setLongpressDelay('+delay+')');
|
||||
} else {
|
||||
window.console.log('setLongpressDelay error: keyman.osk undefined');
|
||||
}
|
||||
}
|
||||
|
||||
// Update the KMW banner height
|
||||
// h is in dpi (different from iOS)
|
||||
function setBannerHeight(h) {
|
||||
|
|
@ -125,7 +152,7 @@ function setOskHeight(h) {
|
|||
|
||||
function setOskWidth(w) {
|
||||
if(w > 0) {
|
||||
oskWidth = w;
|
||||
oskWidth = w / window.devicePixelRatio;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +199,8 @@ function setKeymanLanguage(k) {
|
|||
}
|
||||
|
||||
function setSpacebarText(mode) {
|
||||
keyman.config.spacebarText = mode;
|
||||
var text = (mode == undefined) || !mode.text ? '' : mode.text;
|
||||
keyman.config.spacebarText = text;
|
||||
}
|
||||
|
||||
// #6665: we need to know when the user has pressed a hardware key so we don't
|
||||
|
|
@ -230,10 +258,8 @@ function setNumericLayer() {
|
|||
}
|
||||
}
|
||||
|
||||
function updateKMText(text) {
|
||||
if(text == undefined) {
|
||||
text = '';
|
||||
}
|
||||
function updateKMText(k) {
|
||||
var text = (k == undefined) || !k.text ? '' : k.text;
|
||||
|
||||
console_debug('updateKMText(text=' + text + ') with: \n' + build_context_string(keyman.context));
|
||||
|
||||
|
|
@ -278,7 +304,7 @@ function updateKMSelectionRange(start, end) {
|
|||
|
||||
console_debug('result:\n' + build_context_string(context));
|
||||
} else {
|
||||
console.debug('range unchanged');
|
||||
console_debug('range unchanged');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +344,14 @@ function menuKeyUp() {
|
|||
window.location.hash = hash;
|
||||
}
|
||||
|
||||
// The keyboard-picker displayed via Android longpress disrupts Web-side
|
||||
// gesture-handling; this function helps force-clear the globe key's highlighting.
|
||||
function clearGlobeHighlight() {
|
||||
if(keyman.osk && keyman.osk.vkbd && keyman.osk.vkbd.currentLayer.globeKey) {
|
||||
keyman.osk.vkbd.currentLayer.globeKey.highlight(false)
|
||||
}
|
||||
}
|
||||
|
||||
function hideKeyboard() {
|
||||
fragmentToggle = (fragmentToggle + 1) % 100;
|
||||
window.location.hash = 'hideKeyboard' + fragmentToggle;
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright (C) 2017-2019 SIL International. All rights reserved.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<title>Keyman</title>
|
||||
<!-- Provides polyfills needed by un-updated Chromium versions found
|
||||
on older, but still-supported, Android APIs.
|
||||
|
||||
If and when our minimum supported Android version shipped with
|
||||
Chromium version 54 or greater, we should be able to drop this
|
||||
polyfill.
|
||||
-->
|
||||
<script src="es6-shim.min.js"></script>
|
||||
<script src="other-polyfills.js"></script>
|
||||
<script src="map-polyfill.js"></script>
|
||||
<script src="keymanweb-webview.es5.js"></script>
|
||||
<script src="sentry.min.js"></script>
|
||||
<script src="keyman-sentry.js"></script>
|
||||
<script src="android-host.js"></script>
|
||||
<style type="text/css">
|
||||
body {background-color:#000000;}
|
||||
</style>
|
||||
</head>
|
||||
<body class="kmw-embedded keyman-app">
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -7,6 +7,8 @@
|
|||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<title>Keyman</title>
|
||||
<!-- DOMRect only exists as of Chrome 61... thus coming later than ES6. -->
|
||||
<script src="other-polyfills.js"></script>
|
||||
<script src="keymanweb-webview.js"></script>
|
||||
<script src="sentry.min.js"></script>
|
||||
<script src="keyman-sentry.js"></script>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class DisplayLanguages {
|
|||
DisplayLanguageType[] languages = {
|
||||
new DisplayLanguageType(unspecifiedLocale, context.getString(R.string.default_locale)),
|
||||
new DisplayLanguageType("am-ET", "አማርኛ (Amharic)"),
|
||||
new DisplayLanguageType("ar-SA", "(Arabic) العربية"),
|
||||
new DisplayLanguageType("az-AZ", "Azərbaycanca (Azəricə)"),
|
||||
new DisplayLanguageType("bwr-NG", "Bura-Pabir"),
|
||||
new DisplayLanguageType("cs-CZ", "čeština (Czech)"),
|
||||
|
|
@ -62,6 +63,7 @@ public class DisplayLanguages {
|
|||
new DisplayLanguageType("nl-NL", "Nederlands (Dutch)"),
|
||||
new DisplayLanguageType("ann", "Obolo"),
|
||||
new DisplayLanguageType("pl-PL", "Polski (Polish)"),
|
||||
new DisplayLanguageType("el", "Polytonic Greek"),
|
||||
new DisplayLanguageType("pt-PT", "Português do Portugal"),
|
||||
new DisplayLanguageType("ff-ZA", "Pulaar-Fulfulde"), // or Fulah
|
||||
new DisplayLanguageType("ru-RU", "Pyccĸий (Russian)"),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import android.content.Context;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
|
|
@ -149,13 +150,19 @@ final class KMKeyboard extends WebView {
|
|||
|
||||
protected boolean updateText(String text) {
|
||||
boolean result = false;
|
||||
JSONObject reg = new JSONObject();
|
||||
String kmText = "";
|
||||
if (text != null) {
|
||||
kmText = text.toString().replace("\\", "\\u005C").replace("'", "\\u0027").replace("\n", "\\n");
|
||||
// Use JSON to handle passing string to Javascript
|
||||
try {
|
||||
reg.put("text", text.toString());
|
||||
} catch (JSONException e) {
|
||||
KMLog.LogException(TAG, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (KMManager.isKeyboardLoaded(this.keyboardType) && !shouldIgnoreTextChange) {
|
||||
this.loadJavascript(KMString.format("updateKMText('%s')", kmText));
|
||||
this.loadJavascript(KMString.format("updateKMText(%s)", reg.toString()));
|
||||
result = true;
|
||||
}
|
||||
|
||||
|
|
@ -163,41 +170,69 @@ final class KMKeyboard extends WebView {
|
|||
return result;
|
||||
}
|
||||
|
||||
protected boolean updateSelectionRange(int selStart, int selEnd) {
|
||||
boolean result = false;
|
||||
/**
|
||||
* Updates the selection range of the current context.
|
||||
* Returns boolean - true if the selection range was updated successfully
|
||||
*/
|
||||
protected boolean updateSelectionRange() {
|
||||
|
||||
InputConnection ic = KMManager.getInputConnection(this.keyboardType);
|
||||
if (ic != null) {
|
||||
ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
|
||||
if (icText == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String rawText = icText.text.toString();
|
||||
updateText(rawText.toString());
|
||||
|
||||
/*
|
||||
The values of selStart & selEnd provided by the system are in code units,
|
||||
not code-points. We need to account for surrogate pairs here.
|
||||
|
||||
Fortunately, it uses UCS-2 encoding... just like JS.
|
||||
|
||||
References:
|
||||
- https://stackoverflow.com/a/23980211
|
||||
- https://android.googlesource.com/platform/frameworks/base/+/152944f/core/java/android/view/inputmethod/InputConnection.java#326
|
||||
*/
|
||||
|
||||
// Count the number of characters which are surrogate pairs.
|
||||
int pairsAtStart = CharSequenceUtil.countSurrogatePairs(rawText.substring(0, selStart), rawText.length());
|
||||
String selectedText = rawText.substring(selStart, selEnd);
|
||||
int pairsSelected = CharSequenceUtil.countSurrogatePairs(selectedText, selectedText.length());
|
||||
|
||||
selStart -= pairsAtStart;
|
||||
selEnd -= (pairsAtStart + pairsSelected);
|
||||
if (ic == null) {
|
||||
// Unable to get connection to the text
|
||||
return false;
|
||||
}
|
||||
this.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selStart, selEnd));
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
ExtractedText icText = ic.getExtractedText(new ExtractedTextRequest(), 0);
|
||||
if (icText == null) {
|
||||
// Failed to get text becausee either input connection became invalid or client is taking too long to respond
|
||||
// https://developer.android.com/reference/android/view/inputmethod/InputConnection#getExtractedText(android.view.inputmethod.ExtractedTextRequest,%20int)
|
||||
return false;
|
||||
}
|
||||
|
||||
String rawText = icText.text.toString();
|
||||
updateText(rawText.toString());
|
||||
|
||||
int selMin = icText.selectionStart, selMax = icText.selectionEnd;
|
||||
|
||||
int textLength = rawText.length();
|
||||
|
||||
if (selMin < 0 || selMax < 0) {
|
||||
// There is no selection or cursor
|
||||
// Reference https://developer.android.com/reference/android/text/Selection#getSelectionEnd(java.lang.CharSequence)
|
||||
return false;
|
||||
} else if (selMin > textLength || selMax > textLength) {
|
||||
// Selection is past end of existing text -- should not be possible but we
|
||||
// are seeing it happen; #11506
|
||||
return false;
|
||||
}
|
||||
|
||||
if (selMin > selMax) {
|
||||
// Selection is reversed so "swap"
|
||||
selMin = icText.selectionEnd;
|
||||
selMax = icText.selectionStart;
|
||||
}
|
||||
|
||||
/*
|
||||
The values of selStart & selEnd provided by the system are in code units,
|
||||
not code-points. We need to account for surrogate pairs here.
|
||||
|
||||
Fortunately, it uses UCS-2 encoding... just like JS.
|
||||
|
||||
References:
|
||||
- https://stackoverflow.com/a/23980211
|
||||
- https://android.googlesource.com/platform/frameworks/base/+/152944f/core/java/android/view/inputmethod/InputConnection.java#326
|
||||
*/
|
||||
|
||||
// Count the number of characters which are surrogate pairs.
|
||||
int pairsAtStart = CharSequenceUtil.countSurrogatePairs(rawText.substring(0, selMin), rawText.length());
|
||||
String selectedText = rawText.substring(selMin, selMax);
|
||||
int pairsSelected = CharSequenceUtil.countSurrogatePairs(selectedText, selectedText.length());
|
||||
|
||||
selMin -= pairsAtStart;
|
||||
selMax -= (pairsAtStart + pairsSelected);
|
||||
this.loadJavascript(KMString.format("updateKMSelectionRange(%d,%d)", selMin, selMax));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -219,10 +254,17 @@ final class KMKeyboard extends WebView {
|
|||
|
||||
getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
getSettings().setSupportZoom(false);
|
||||
getSettings().setTextZoom(100);
|
||||
|
||||
getSettings().setUseWideViewPort(true);
|
||||
getSettings().setLoadWithOverviewMode(true);
|
||||
if (0 != (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)) {
|
||||
|
||||
// When `.isTestMode() == true`, the setWebContentsDebuggingEnabled method is not available
|
||||
// and thus will trigger unit-test failures.
|
||||
if (!KMManager.isTestMode() && (
|
||||
(context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 ||
|
||||
KMManager.getTier(null) != KMManager.Tier.STABLE
|
||||
)) {
|
||||
// Enable debugging of WebView via adb. Not used during unit tests
|
||||
// Refer: https://developer.chrome.com/docs/devtools/remote-debugging/webviews/#configure_webviews_for_debugging
|
||||
setWebContentsDebuggingEnabled(true);
|
||||
|
|
@ -271,6 +313,12 @@ final class KMKeyboard extends WebView {
|
|||
public void onLongPress(MotionEvent event) {
|
||||
if (KMManager.getGlobeKeyState() == KMManager.GlobeKeyState.GLOBE_KEY_STATE_DOWN) {
|
||||
KMManager.setGlobeKeyState(KMManager.GlobeKeyState.GLOBE_KEY_STATE_LONGPRESS);
|
||||
|
||||
// When we activate the keyboard picker, this will disrupt the JS-side's control
|
||||
// flow for gesture-handling; we should pre-emptively clear the globe key,
|
||||
// as Web will not receive a "globe key up" event.
|
||||
loadJavascript("clearGlobeHighlight()");
|
||||
|
||||
KMManager.handleGlobeKeyAction(context, true, keyboardType);
|
||||
return;
|
||||
/* For future implementation
|
||||
|
|
@ -334,7 +382,8 @@ final class KMKeyboard extends WebView {
|
|||
allCalls.append(";");
|
||||
}
|
||||
|
||||
loadUrl("javascript:" + allCalls.toString());
|
||||
// Ensure strings safe for Javascript. TODO: font strings
|
||||
loadUrl("javascript:" + Uri.encode(allCalls.toString()));
|
||||
|
||||
if(javascriptAfterLoad.size() > 0 && keyboardSet) {
|
||||
callJavascriptAfterLoad();
|
||||
|
|
@ -400,20 +449,15 @@ final class KMKeyboard extends WebView {
|
|||
dismissHelpBubble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
RelativeLayout.LayoutParams params = KMManager.getKeyboardLayoutParams();
|
||||
// I suspect this is the part we should actually be calling directly...
|
||||
this.setLayoutParams(params);
|
||||
|
||||
int bannerHeight = KMManager.getBannerHeight(context);
|
||||
int oskHeight = KMManager.getKeyboardHeight(context);
|
||||
if (this.htmlBannerString != null && !this.htmlBannerString.isEmpty()) {
|
||||
setHTMLBanner(this.htmlBannerString);
|
||||
}
|
||||
loadJavascript(KMString.format("setBannerHeight(%d)", bannerHeight));
|
||||
loadJavascript(KMString.format("setOskWidth(%d)", newConfig.screenWidthDp));
|
||||
loadJavascript(KMString.format("setOskHeight(%d)", oskHeight));
|
||||
this.invalidate();
|
||||
this.requestLayout();
|
||||
|
||||
this.dismissHelpBubble();
|
||||
|
||||
|
|
@ -422,6 +466,27 @@ final class KMKeyboard extends WebView {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
int bannerHeight = KMManager.getBannerHeight(context);
|
||||
int oskHeight = KMManager.getKeyboardHeight(context);
|
||||
|
||||
if(bannerHeight + oskHeight != height) {
|
||||
// We'll proceed, but cautiously and with logging.
|
||||
KMLog.LogInfo(TAG, "Height mismatch: onSizeChanged = " + height + ", our version = " + (bannerHeight + oskHeight));
|
||||
}
|
||||
|
||||
if (this.htmlBannerString != null && !this.htmlBannerString.isEmpty()) {
|
||||
setHTMLBanner(this.htmlBannerString);
|
||||
}
|
||||
|
||||
loadJavascript(KMString.format("setBannerHeight(%d)", bannerHeight));
|
||||
loadJavascript(KMString.format("setOskWidth(%d)", width));
|
||||
// Must be last - it's the one that triggers a Web-engine layout refresh.
|
||||
loadJavascript(KMString.format("setOskHeight(%d)", oskHeight));
|
||||
}
|
||||
|
||||
public void dismissSuggestionMenuWindow() {
|
||||
try {
|
||||
if (suggestionMenuWindow != null && suggestionMenuWindow.isShowing()) {
|
||||
|
|
@ -870,10 +935,7 @@ final class KMKeyboard extends WebView {
|
|||
rotateSuggestions.setClickable(false);
|
||||
|
||||
// Compute the actual display position (offset coordinate by actual screen pos of kbd)
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(metrics);
|
||||
float density = metrics.density;
|
||||
float density = KMManager.getWindowDensity(context);
|
||||
|
||||
int posX, posY;
|
||||
if (keyboardType == KeyboardType.KEYBOARD_TYPE_INAPP) {
|
||||
|
|
@ -1082,8 +1144,17 @@ final class KMKeyboard extends WebView {
|
|||
}
|
||||
|
||||
public void setSpacebarText(KMManager.SpacebarText mode) {
|
||||
String jsString = KMString.format("setSpacebarText('%s')", mode.toString());
|
||||
loadJavascript(jsString);
|
||||
JSONObject reg = new JSONObject();
|
||||
if (mode != null) {
|
||||
// Use JSON to handle passing string to Javascript
|
||||
try {
|
||||
reg.put("text", mode.toString());
|
||||
} catch (JSONException e) {
|
||||
KMLog.LogException(TAG, "", e);
|
||||
}
|
||||
}
|
||||
|
||||
this.loadJavascript(KMString.format("setSpacebarText(%s)", reg.toString()));
|
||||
}
|
||||
|
||||
/* Implement handleTouchEvent to catch long press gesture without using Android system default time
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import android.webkit.JavascriptInterface;
|
|||
|
||||
import static android.content.Context.VIBRATOR_SERVICE;
|
||||
|
||||
import com.keyman.engine.KMManager.EnterModeType;
|
||||
import com.keyman.engine.KMManager.KeyboardType;
|
||||
import com.keyman.engine.data.Keyboard;
|
||||
import com.keyman.engine.util.CharSequenceUtil;
|
||||
|
|
@ -135,13 +136,13 @@ public class KMKeyboardJSHandler {
|
|||
end = temp;
|
||||
}
|
||||
if (end > start) {
|
||||
k.setShouldIgnoreSelectionChange(true);
|
||||
if (s.length() == 0) {
|
||||
ic.setSelection(start, start);
|
||||
ic.deleteSurroundingText(0, end - start);
|
||||
ic.endBatchEdit();
|
||||
return;
|
||||
} else {
|
||||
k.setShouldIgnoreSelectionChange(true);
|
||||
ic.setSelection(start, start);
|
||||
ic.deleteSurroundingText(0, end - start);
|
||||
}
|
||||
|
|
@ -153,7 +154,53 @@ public class KMKeyboardJSHandler {
|
|||
}
|
||||
|
||||
if (s.length() > 0 && s.charAt(0) == '\n') {
|
||||
keyDownUp(KeyEvent.KEYCODE_ENTER, 0);
|
||||
if (k.keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM) {
|
||||
// Special handling of ENTER key
|
||||
switch (KMManager.enterMode) {
|
||||
// Go action
|
||||
case GO :
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_GO);
|
||||
break;
|
||||
|
||||
// Search action
|
||||
case SEARCH :
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_SEARCH);
|
||||
break;
|
||||
|
||||
// Send action
|
||||
case SEND :
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_SEND);
|
||||
break;
|
||||
|
||||
// Next action
|
||||
case NEXT :
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
|
||||
break;
|
||||
|
||||
// Done action
|
||||
case DONE :
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_DONE);
|
||||
break;
|
||||
|
||||
// Previous action
|
||||
case PREVIOUS :
|
||||
ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
|
||||
break;
|
||||
|
||||
// Messaging apps
|
||||
case NEWLINE :
|
||||
// Send newline and advance cursor
|
||||
ic.commitText("\n", 1);
|
||||
break;
|
||||
|
||||
// Default ENTER action
|
||||
default:
|
||||
keyDownUp(KeyEvent.KEYCODE_ENTER, 0);
|
||||
}
|
||||
} else {
|
||||
// In-app keyboard uses default ENTER action
|
||||
keyDownUp(KeyEvent.KEYCODE_ENTER, 0);
|
||||
}
|
||||
ic.endBatchEdit();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.graphics.Point;
|
||||
import android.graphics.Typeface;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.net.ConnectivityManager;
|
||||
|
|
@ -32,6 +33,7 @@ import android.net.NetworkInfo;
|
|||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.text.InputType;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Display;
|
||||
|
|
@ -39,6 +41,7 @@ import android.view.Surface;
|
|||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowMetrics;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
|
@ -176,6 +179,19 @@ public final class KMManager {
|
|||
}
|
||||
}
|
||||
|
||||
// Enum for how the System Keyboard ENTER key is handled for the EditorInfo action
|
||||
// Reference: https://developer.android.com/reference/android/view/inputmethod/EditorInfo#summary
|
||||
public enum EnterModeType {
|
||||
GO, // Go action
|
||||
SEARCH, // Search action
|
||||
SEND, // Send action
|
||||
NEXT, // Next action
|
||||
DONE, // Done action
|
||||
PREVIOUS, // Previous action
|
||||
NEWLINE, // Send newline character
|
||||
DEFAULT, // Default ENTER action
|
||||
}
|
||||
|
||||
protected static InputMethodService IMService;
|
||||
|
||||
private static boolean debugMode = false;
|
||||
|
|
@ -214,6 +230,9 @@ public final class KMManager {
|
|||
// regardless what the Settings preference is.
|
||||
private static boolean mayPredictOverride = false;
|
||||
|
||||
// Determine how system keyboard handles ENTER key
|
||||
public static EnterModeType enterMode = EnterModeType.DEFAULT;
|
||||
|
||||
// Boolean for whether a keyboard can send embedded KMW crash reports to Sentry
|
||||
// When maySendCrashReport is false, KMW will still attempt to send crash reports, but it
|
||||
// will be blocked.
|
||||
|
|
@ -244,6 +263,8 @@ public final class KMManager {
|
|||
public static final String KMKey_KeyboardHeightPortrait = "keyboardHeightPortrait";
|
||||
public static final String KMKey_KeyboardHeightLandscape = "keyboardHeightLandscape";
|
||||
|
||||
public static final String KMKey_LongpressDelay = "longpressDelay";
|
||||
|
||||
public static final String KMKey_CustomHelpLink = "CustomHelpLink";
|
||||
public static final String KMKey_KMPLink = "kmp";
|
||||
public static final String KMKey_UserKeyboardIndex = "UserKeyboardIndex";
|
||||
|
|
@ -289,11 +310,15 @@ public final class KMManager {
|
|||
public static final String KMDefault_DictionaryVersion = "0.1.4";
|
||||
public static final String KMDefault_DictionaryKMP = KMDefault_DictionaryPackageID + FileUtils.MODELPACKAGE;
|
||||
|
||||
// Default KeymanWeb longpress delay constants in milliseconds
|
||||
public static final int KMDefault_LongpressDelay = 500;
|
||||
public static final int KMMinimum_LongpressDelay = 300;
|
||||
public static final int KMMaximum_LongpressDelay = 1500;
|
||||
|
||||
|
||||
// Keyman files
|
||||
protected static final String KMFilename_KeyboardHtml = "keyboard.html";
|
||||
protected static final String KMFilename_KeyboardHtml_Legacy = "keyboard.es5.html";
|
||||
protected static final String KMFilename_JSEngine = "keymanweb-webview.js";
|
||||
protected static final String KMFilename_JSLegacyEngine = "keymanweb-webview.es5.js";
|
||||
protected static final String KMFilename_JSSentry = "sentry.min.js";
|
||||
protected static final String KMFilename_JSSentryInit = "keyman-sentry.js";
|
||||
protected static final String KMFilename_AndroidHost = "android-host.js";
|
||||
|
|
@ -854,25 +879,11 @@ public final class KMManager {
|
|||
private static void copyAssets(Context context) {
|
||||
AssetManager assetManager = context.getAssets();
|
||||
|
||||
// Will build a temp WebView in order to check Chrome version internally.
|
||||
boolean legacyMode = WebViewUtils.getEngineWebViewVersionStatus(context, null, null) != WebViewUtils.EngineWebViewVersionStatus.FULL;
|
||||
|
||||
try {
|
||||
// Copy KMW files
|
||||
if(legacyMode) {
|
||||
// Replaces the standard ES6-friendly version of the host page with a legacy one that
|
||||
// includes polyfill requests and that links the legacy, ES5-compatible version of KMW.
|
||||
copyAssetWithRename(context, KMFilename_KeyboardHtml_Legacy, KMFilename_KeyboardHtml, "", true);
|
||||
copyAsset(context, KMFilename_KeyboardHtml, "", true);
|
||||
|
||||
copyAsset(context, KMFilename_JSLegacyEngine, "", true);
|
||||
} else {
|
||||
copyAsset(context, KMFilename_KeyboardHtml, "", true);
|
||||
|
||||
// For versions of Chrome with full ES6 support, we use the ES6 artifact.
|
||||
copyAsset(context, KMFilename_JSEngine, "", true);
|
||||
}
|
||||
|
||||
// Is still built targeting ES5.
|
||||
copyAsset(context, KMFilename_JSEngine, "", true);
|
||||
copyAsset(context, KMFilename_JSSentry, "", true);
|
||||
copyAsset(context, KMFilename_JSSentryInit, "", true);
|
||||
copyAsset(context, KMFilename_AndroidHost, "", true);
|
||||
|
|
@ -883,12 +894,6 @@ public final class KMManager {
|
|||
// Copy default keyboard font
|
||||
copyAsset(context, KMDefault_KeyboardFont, "", true);
|
||||
|
||||
if(legacyMode) {
|
||||
copyAsset(context, KMFilename_JSPolyfill, "", true);
|
||||
copyAsset(context, KMFilename_JSPolyfill2, "", true);
|
||||
copyAsset(context, KMFilename_JSPolyfill3, "", true);
|
||||
}
|
||||
|
||||
// Keyboard packages directory
|
||||
File packagesDir = new File(getPackagesDir());
|
||||
if (!packagesDir.exists()) {
|
||||
|
|
@ -1269,6 +1274,60 @@ public final class KMManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets enterMode which specifies how the System keyboard ENTER key is handled
|
||||
*
|
||||
* @param imeOptions EditorInfo.imeOptions used to determine the action
|
||||
* @param inputType InputType used to determine if the text field is multi-line
|
||||
*/
|
||||
public static void setEnterMode(int imeOptions, int inputType) {
|
||||
EnterModeType value = EnterModeType.DEFAULT;
|
||||
int imeActions = imeOptions & EditorInfo.IME_MASK_ACTION;
|
||||
boolean isMultiLine = (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
|
||||
|
||||
switch (imeActions) {
|
||||
case EditorInfo.IME_ACTION_GO:
|
||||
value = EnterModeType.GO;
|
||||
break;
|
||||
|
||||
case EditorInfo.IME_ACTION_SEARCH:
|
||||
value = EnterModeType.SEARCH;
|
||||
break;
|
||||
|
||||
case EditorInfo.IME_ACTION_SEND:
|
||||
value = isMultiLine ?
|
||||
EnterModeType.NEWLINE :EnterModeType.SEND;
|
||||
break;
|
||||
|
||||
case EditorInfo.IME_ACTION_NEXT:
|
||||
value = EnterModeType.NEXT;
|
||||
break;
|
||||
|
||||
case EditorInfo.IME_ACTION_DONE:
|
||||
value = isMultiLine ?
|
||||
EnterModeType.NEWLINE : EnterModeType.DONE;
|
||||
break;
|
||||
|
||||
case EditorInfo.IME_ACTION_PREVIOUS:
|
||||
value = EnterModeType.PREVIOUS;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = isMultiLine ?
|
||||
EnterModeType.NEWLINE : EnterModeType.DEFAULT;
|
||||
}
|
||||
|
||||
enterMode = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of enterMode
|
||||
* @return EnterModeType
|
||||
*/
|
||||
public static EnterModeType getEnterMode() {
|
||||
return enterMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets mayPredictOverride true if the InputType field is a hidden password text field
|
||||
* (either TYPE_TEXT_VARIATION_PASSWORD or TYPE_TEXT_VARIATION_WEB_PASSWORD
|
||||
|
|
@ -1634,7 +1693,7 @@ public final class KMManager {
|
|||
|
||||
public static boolean isDefaultKey(String key) {
|
||||
return (
|
||||
key != null &&
|
||||
key != null &&
|
||||
key.equals(KMString.format("%s_%s", KMDefault_LanguageID, KMDefault_KeyboardID)));
|
||||
}
|
||||
|
||||
|
|
@ -2005,7 +2064,20 @@ public final class KMManager {
|
|||
}
|
||||
|
||||
public static int getOrientation(Context context) {
|
||||
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
||||
Display display;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
// https://developer.android.com/reference/android/content/Context#getDisplay()
|
||||
try {
|
||||
display = context.getDisplay();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// if the method is called on an instance that is not associated with any display.
|
||||
return context.getResources().getConfiguration().orientation;
|
||||
}
|
||||
} else {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
// Deprecated in API 30
|
||||
display = wm.getDefaultDisplay();
|
||||
}
|
||||
int rotation = display.getRotation();
|
||||
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
|
||||
return Configuration.ORIENTATION_PORTRAIT;
|
||||
|
|
@ -2015,6 +2087,53 @@ public final class KMManager {
|
|||
return Configuration.ORIENTATION_UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the longpress delay (in milliseconds) from stored preference. Defaults to 500ms
|
||||
* @return int - longpress delay in milliseconds
|
||||
*/
|
||||
public static int getLongpressDelay() {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(
|
||||
appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
|
||||
return prefs.getInt(KMKey_LongpressDelay, KMDefault_LongpressDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the longpress delay (in milliseconds) as a stored preference.
|
||||
* Valid range is 300 ms to 1500 ms. Returns true if the preference is successfully stored.
|
||||
* @param longpressDelay - int longpress delay in milliseconds
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean setLongpressDelay(int longpressDelay) {
|
||||
if (longpressDelay < KMMinimum_LongpressDelay || longpressDelay > KMMaximum_LongpressDelay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(
|
||||
appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putInt(KMKey_LongpressDelay, longpressDelay);
|
||||
editor.commit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends options to the KeymanWeb keyboard.
|
||||
* 1. number of milliseconds to trigger a longpress gesture.
|
||||
* This method requires a keyboard to be loaded for the value to take effect.
|
||||
*/
|
||||
public static void sendOptionsToKeyboard() {
|
||||
int longpressDelay = getLongpressDelay();
|
||||
if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP)) {
|
||||
InAppKeyboard.loadJavascript(KMString.format("setLongpressDelay(%d)", longpressDelay));
|
||||
}
|
||||
|
||||
if (SystemKeyboard != null) {
|
||||
SystemKeyboard.loadJavascript(KMString.format("setLongpressDelay(%d)", longpressDelay));
|
||||
}
|
||||
}
|
||||
|
||||
public static int getBannerHeight(Context context) {
|
||||
int bannerHeight = 0;
|
||||
if (InAppKeyboard != null && InAppKeyboard.getBanner() != BannerType.BLANK) {
|
||||
|
|
@ -2052,6 +2171,34 @@ public final class KMManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the area the window would occupy.
|
||||
* API 30+
|
||||
* https://developer.android.com/reference/android/view/WindowManager#getCurrentWindowMetrics()
|
||||
* @param context
|
||||
* @return Point (width, height)
|
||||
*/
|
||||
public static Point getWindowSize(Context context) {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
|
||||
// Deprecated in API 30
|
||||
Point size = new Point(0, 0);
|
||||
wm.getDefaultDisplay().getSize(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
|
||||
return new Point(
|
||||
windowMetrics.getBounds().width(),
|
||||
windowMetrics.getBounds().height());
|
||||
}
|
||||
|
||||
public static float getWindowDensity(Context context) {
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
Log.d(TAG, "KMManager: metrics.density " + metrics.density);
|
||||
return metrics.density;
|
||||
}
|
||||
|
||||
protected static void setPersistentShouldShowHelpBubble(boolean flag) {
|
||||
SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
|
@ -2137,17 +2284,40 @@ public final class KMManager {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the active range for selected text.
|
||||
* @deprecated
|
||||
* This method no longer needs the `selStart` and `selEnd` parameters.
|
||||
* <p>Use {@link KMManager#updateSelectionRange(KeyboardType)} instead.</p>
|
||||
*
|
||||
* @param kbType A value indicating if this request is for the in-app keyboard or the system keyboard
|
||||
* @param selStart (deprecated) the start index for the range
|
||||
* @param selEnd (deprecated) the end index for the selected range
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean updateSelectionRange(KeyboardType kbType, int selStart, int selEnd) {
|
||||
return updateSelectionRange(kbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a synchronization check for the active range for selected text,
|
||||
* ensuring it matches the text-editor's current state.
|
||||
* @param kbType A value indicating if this request is for the in-app or system keyboard.
|
||||
* @return
|
||||
*/
|
||||
public static boolean updateSelectionRange(KeyboardType kbType) {
|
||||
boolean result = false;
|
||||
|
||||
if (kbType == KeyboardType.KEYBOARD_TYPE_INAPP) {
|
||||
if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_INAPP) && !InAppKeyboard.shouldIgnoreSelectionChange()) {
|
||||
result = InAppKeyboard.updateSelectionRange(selStart, selEnd);
|
||||
result = InAppKeyboard.updateSelectionRange();
|
||||
}
|
||||
|
||||
InAppKeyboard.setShouldIgnoreSelectionChange(false);
|
||||
} else if (kbType == KeyboardType.KEYBOARD_TYPE_SYSTEM) {
|
||||
if (isKeyboardLoaded(KeyboardType.KEYBOARD_TYPE_SYSTEM) && !SystemKeyboard.shouldIgnoreSelectionChange()) {
|
||||
result = SystemKeyboard.updateSelectionRange(selStart, selEnd);
|
||||
result = SystemKeyboard.updateSelectionRange();
|
||||
}
|
||||
|
||||
SystemKeyboard.setShouldIgnoreSelectionChange(false);
|
||||
|
|
@ -2338,7 +2508,7 @@ public final class KMManager {
|
|||
if (KMManager.shouldAllowSetKeyboard()) {
|
||||
// inKeyguardRestrictedInputMode() deprecated, so check isKeyguardLocked() to determine if screen is locked
|
||||
if (isLocked()) {
|
||||
if (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM && globeKeyState == GlobeKeyState.GLOBE_KEY_STATE_UP) {
|
||||
if (keyboardType == KeyboardType.KEYBOARD_TYPE_SYSTEM && globeKeyState == GlobeKeyState.GLOBE_KEY_STATE_DOWN) {
|
||||
doGlobeKeyLockscreenAction(context);
|
||||
}
|
||||
// clear globeKeyState
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import android.graphics.LinearGradient;
|
|||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
|
|
@ -31,13 +32,11 @@ final class KMPopoverView extends View {
|
|||
|
||||
public KMPopoverView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(metrics);
|
||||
density = metrics.density;
|
||||
Point size = KMManager.getWindowSize(context);
|
||||
density = KMManager.getWindowDensity(context);
|
||||
|
||||
viewWidth = metrics.widthPixels;
|
||||
viewHeight = metrics.heightPixels;
|
||||
viewWidth = size.x;
|
||||
viewHeight = size.y;
|
||||
borderRadius = 6 * density;
|
||||
strokeWidth = 2.0f;
|
||||
bgColor = context.getResources().getColor(R.color.popup_bg);
|
||||
|
|
|
|||
|
|
@ -63,10 +63,8 @@ public final class KMTextView extends AppCompatEditText {
|
|||
*/
|
||||
public static void updateTextContext() {
|
||||
KMTextView textView = (KMTextView) activeView;
|
||||
int selStart = textView.getSelectionStart();
|
||||
int selEnd = textView.getSelectionEnd();
|
||||
KMManager.updateText(KeyboardType.KEYBOARD_TYPE_INAPP, textView.getText().toString());
|
||||
if (KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_INAPP, selStart, selEnd)) {
|
||||
if (KMManager.updateSelectionRange(KeyboardType.KEYBOARD_TYPE_INAPP)) {
|
||||
KMManager.resetContext(KeyboardType.KEYBOARD_TYPE_INAPP);
|
||||
}
|
||||
}
|
||||
|
|
@ -167,7 +165,7 @@ public final class KMTextView extends AppCompatEditText {
|
|||
protected void onSelectionChanged(int selStart, int selEnd) {
|
||||
super.onSelectionChanged(selStart, selEnd);
|
||||
if (activeView != null && activeView.equals(this)) {
|
||||
if (KMManager.updateSelectionRange(KMManager.KeyboardType.KEYBOARD_TYPE_INAPP, selStart, selEnd)) {
|
||||
if (KMManager.updateSelectionRange(KMManager.KeyboardType.KEYBOARD_TYPE_INAPP)) {
|
||||
KMManager.resetContext(KeyboardType.KEYBOARD_TYPE_INAPP);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public final class KeyboardInfoActivity extends BaseActivity {
|
|||
hashMap = new HashMap<String, String>();
|
||||
final String customHelpLink = kbd.getHelpLink();
|
||||
// Check if app declared FileProvider
|
||||
String icon = String.valueOf(R.drawable.ic_arrow_forward);
|
||||
String icon = String.valueOf(R.drawable.ic_action_forward);
|
||||
// Don't show help link arrow if it's a local help file and File Provider unavailable,
|
||||
// or custom help doesn't exist
|
||||
if ( (customHelpLink != null && ! KMManager.isTestMode() &&
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ public final class KeyboardPickerActivity extends BaseActivity {
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public final class ModelInfoActivity extends BaseActivity {
|
|||
final String customHelpLink = lm.getHelpLink();
|
||||
// Check if app declared FileProvider
|
||||
// Currently, model help only available if custom link exists
|
||||
icon = String.valueOf(R.drawable.ic_arrow_forward);
|
||||
icon = String.valueOf(R.drawable.ic_action_forward);
|
||||
// Don't show help link arrow if both custom help and File Provider don't exist
|
||||
// TODO: Update this when model help available on help.keyman.com
|
||||
if ( (!customHelpLink.equals("") && !FileProviderUtils.exists(context)) ||
|
||||
|
|
|
|||
|
|
@ -273,6 +273,7 @@ public final class ModelPickerActivity extends BaseActivity {
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +321,7 @@ public final class ModelPickerActivity extends BaseActivity {
|
|||
// once it has its own backing Dataset instance.
|
||||
// Is this an installed model or not?
|
||||
|
||||
holder.imgDetails.setImageResource(R.drawable.ic_arrow_forward);
|
||||
holder.imgDetails.setImageResource(R.drawable.ic_action_forward);
|
||||
if (KeyboardPickerActivity.containsLexicalModel(context, modelKey)) {
|
||||
holder.imgInstalled.setImageResource(R.drawable.ic_check);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class CloudDownloadMgr{
|
|||
{
|
||||
if(instance!=null)
|
||||
return;
|
||||
KMLog.LogBreadcrumb("CloudDownloadMgr", "CloudDownloadMgr.createInstance() - first call", true);
|
||||
instance = new CloudDownloadMgr();
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +61,7 @@ public class CloudDownloadMgr{
|
|||
if(isInitialized)
|
||||
return;
|
||||
try {
|
||||
KMLog.LogBreadcrumb("CloudDownloadMgr", "attempting CloudDownloadMgr.initialize()", true);
|
||||
// Runtime-registered boradcasts receivers must specify export behavior to indicate whether
|
||||
// or not the receiver should be exported to all other apps on the device
|
||||
// https://developer.android.com/about/versions/14/behavior-changes-14#runtime-receivers-exported
|
||||
|
|
@ -69,11 +71,12 @@ public class CloudDownloadMgr{
|
|||
} else {
|
||||
aContext.registerReceiver(completeListener, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
String message = "initialize error: ";
|
||||
KMLog.LogException(TAG, message, e);
|
||||
}
|
||||
isInitialized = true;
|
||||
KMLog.LogBreadcrumb("CloudDownloadMgr", ".initialize() call complete", false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,11 +85,15 @@ public class CloudDownloadMgr{
|
|||
*/
|
||||
public synchronized void shutdown(Context aContext)
|
||||
{
|
||||
if(!isInitialized)
|
||||
if(!isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
KMLog.LogBreadcrumb("CloudDownloadMgr", "CloudDownloadMgr.shutdown()", true);
|
||||
|
||||
try {
|
||||
aContext.unregisterReceiver(completeListener);
|
||||
} catch (IllegalStateException e) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
String message = "shutdown error: ";
|
||||
KMLog.LogException(TAG, message, e);
|
||||
}
|
||||
|
|
@ -206,8 +213,10 @@ public class CloudDownloadMgr{
|
|||
CloudApiTypes.CloudApiParam... params)
|
||||
{
|
||||
if(!isInitialized) {
|
||||
Log.w(TAG, "Downloadmanager not initialized. Initializing CloudDownloadMgr.");
|
||||
Log.w(TAG, "DownloadManager not initialized. Initializing CloudDownloadMgr.");
|
||||
initialize(aContext);
|
||||
} else {
|
||||
KMLog.LogBreadcrumb("CloudDownloadMgr", "CloudDownloadMgr.executeAsDownload() called; already initialized", true);
|
||||
}
|
||||
|
||||
synchronized (downloadSetByDownloadIdentifier) {
|
||||
|
|
@ -218,7 +227,7 @@ public class CloudDownloadMgr{
|
|||
|
||||
DownloadManager downloadManager = (DownloadManager) aContext.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
if(downloadManager==null)
|
||||
throw new IllegalStateException("Downloadmanager is not available");
|
||||
throw new IllegalStateException("DownloadManager is not available");
|
||||
|
||||
aCallback.initializeContext(aContext);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.keyman.engine.KMManager;
|
|||
import com.keyman.engine.util.DependencyUtil;
|
||||
import com.keyman.engine.util.DependencyUtil.LibraryType;
|
||||
|
||||
import io.sentry.Breadcrumb;
|
||||
import io.sentry.Sentry;
|
||||
import io.sentry.SentryLevel;
|
||||
|
||||
|
|
@ -34,6 +35,48 @@ public final class KMLog {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to log info and add as a Sentry breadcrumb, rather than
|
||||
* as an independent message
|
||||
* @param tag String of the caller
|
||||
* @param msg String of the info message
|
||||
*/
|
||||
public static void LogBreadcrumb(String tag, String msg, boolean addStackTrace) {
|
||||
if (msg == null || msg.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(tag, msg);
|
||||
|
||||
if (!DependencyUtil.libraryExists(LibraryType.SENTRY) || !Sentry.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Breadcrumb crumb = new Breadcrumb();
|
||||
crumb.setMessage(msg);
|
||||
crumb.setLevel(SentryLevel.INFO);
|
||||
|
||||
if(addStackTrace) {
|
||||
StackTraceElement[] rawTrace = Thread.currentThread().getStackTrace();
|
||||
|
||||
// The call that gets us the stack-trace above... shows up in the
|
||||
// stack trace, so we'll skip the first few (redundant) entries.
|
||||
int skipCount = 3;
|
||||
|
||||
// Sentry does limit the size of messages... so let's just
|
||||
// keep 10 entries and call it a day.
|
||||
int limit = Math.min(rawTrace.length, 10 + skipCount);
|
||||
if(rawTrace.length > skipCount) {
|
||||
String[] trace = new String[limit - skipCount];
|
||||
for (int i = skipCount; i < limit; i++) {
|
||||
trace[i-skipCount] = rawTrace[i].toString();
|
||||
}
|
||||
crumb.setData("stacktrace", trace);
|
||||
}
|
||||
}
|
||||
Sentry.addBreadcrumb(crumb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to log error and send to Sentry
|
||||
* @param tag String of the caller
|
||||
|
|
|
|||
BIN
android/KMEA/app/src/main/res/drawable-hdpi/ic_arrow_back.png
Normal file
|
After Width: | Height: | Size: 321 B |
BIN
android/KMEA/app/src/main/res/drawable-mdpi/ic_arrow_back.png
Normal file
|
After Width: | Height: | Size: 270 B |
BIN
android/KMEA/app/src/main/res/drawable-xhdpi/ic_arrow_back.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
android/KMEA/app/src/main/res/drawable-xxhdpi/ic_arrow_back.png
Normal file
|
After Width: | Height: | Size: 352 B |
BIN
android/KMEA/app/src/main/res/drawable-xxxhdpi/ic_arrow_back.png
Normal file
|
After Width: | Height: | Size: 413 B |
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/ic_arrow_back"
|
||||
android:tint="@android:color/black"
|
||||
android:autoMirrored="true" />
|
||||