Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
12b0f8f
fix(settings): fix and optimize gboard import
LeanBitLab Jun 1, 2026
7b626f1
chore: bump version to 3.8.4
LeanBitLab Jun 1, 2026
935f93b
feat(settings): improve text expander ui/ux
LeanBitLab Jun 1, 2026
b1b95f9
feat(settings): polish text expander guide and list
LeanBitLab Jun 1, 2026
fcf830e
feat(settings): clean up text expander guide
LeanBitLab Jun 1, 2026
26ad741
feat(settings): add more expander placeholders
LeanBitLab Jun 1, 2026
980ecf5
feat(settings): add system template placeholders
LeanBitLab Jun 1, 2026
443cea2
feat(settings): add language placeholder
LeanBitLab Jun 1, 2026
48b6978
fix(perf): prevent OOM on background image decode
LeanBitLab Jun 1, 2026
f115d55
fix(stability): replace force-unwrap !! in hot paths
LeanBitLab Jun 1, 2026
3dbf4c7
fix(stability): unregister SharedPreferences listener in spell-checker
LeanBitLab Jun 1, 2026
f9c7e23
fix(stability): don't call Looper.prepare() on background thread
LeanBitLab Jun 1, 2026
6d81417
fix(stability): make score-limit cache update atomic in Suggest
LeanBitLab Jun 1, 2026
8b73400
fix(stability): use named lock for dictionary blacklist
LeanBitLab Jun 1, 2026
c3b1003
perf(perf): add key= to Lazy* list items for stable identity
LeanBitLab Jun 1, 2026
a6fa290
perf(perf): remember() expensive computations in Composables
LeanBitLab Jun 1, 2026
ead818c
perf(perf): avoid Paint allocation per recomposition in ColorPickerDi…
LeanBitLab Jun 1, 2026
b7b17a7
perf(perf): stream logcat to file instead of buffering in memory
LeanBitLab Jun 1, 2026
1c9d550
perf(perf): make ReorderSwitchPreference data class stable
LeanBitLab Jun 1, 2026
8438ac0
fix(perf): remove top-level MutableStateFlow in AIIntegrationScreen
LeanBitLab Jun 1, 2026
dedd3cb
fix(perf): scope errorJob to the LayoutEditDialog composable
LeanBitLab Jun 1, 2026
3a5fd14
fix(perf): replace GlobalScope in toolbar preference listener
LeanBitLab Jun 1, 2026
90e972e
fix(perf): make SettingsNavHost navigateTo scope supervised
LeanBitLab Jun 1, 2026
c1d4de1
fix(stability): replace !! in colorFilter() helper
LeanBitLab Jun 1, 2026
a63b7da
perf(perf): cache main-thread Handler in ClipboardHistoryManager
LeanBitLab Jun 1, 2026
1a84e7a
fix(stability): use SupervisorJob in RichInputMethodManager scope
LeanBitLab Jun 1, 2026
67044de
fix(stability): use ContextCompat.registerReceiver with NOT_EXPORTED …
LeanBitLab Jun 1, 2026
ce755f4
fix(settings): update ai provider fields dynamically
LeanBitLab Jun 4, 2026
82bde3d
feat: add standardOptimised flavor and disable r8
LeanBitLab Jun 4, 2026
ed13c9a
perf: add baseline profile for standardOptimised
LeanBitLab Jun 4, 2026
9a26c73
feat: remove standardOptimised package suffix
LeanBitLab Jun 4, 2026
50f184b
fix: dismiss emoji dialog and update wizard status
LeanBitLab Jun 4, 2026
b559cab
Update ar.txt
iBasim Jun 5, 2026
7c310bf
Update build-debug-apk.yml
iBasim Jun 5, 2026
063d168
arabic-popup-and-harakat-tweak
iBasim Jun 5, 2026
4ed977f
arabic-popup-and-harakat-tweak V2
iBasim Jun 5, 2026
5cc7598
ci: add badge update workflow
LeanBitLab Jun 5, 2026
2e580e8
chore: update README badges [skip ci]
github-actions[bot] Jun 5, 2026
40b79e4
fix: strip leading v from version tag
LeanBitLab Jun 5, 2026
66af68e
chore: update README badges [skip ci]
github-actions[bot] Jun 5, 2026
eb19ef9
fix(badges): adjust width and add viewBox attributes to prevent clipping
LeanBitLab Jun 5, 2026
d27f63a
chore: update README badges [skip ci]
github-actions[bot] Jun 5, 2026
d3d0fa2
chore(badges): rename download badge label to version
LeanBitLab Jun 5, 2026
85a5c6e
chore: update README badges [skip ci]
github-actions[bot] Jun 5, 2026
2f0f956
fix: prevent duplicate screenshots in clipboard
LeanBitLab Jun 5, 2026
1473796
feat: add toggle for screenshot compression
LeanBitLab Jun 5, 2026
fbb8de7
feat: improve text expander, gestures, and emoji scale fit
LeanBitLab Jun 5, 2026
d4a6884
chore: update README badges [skip ci]
github-actions[bot] Jun 6, 2026
5d41769
fix: persist toolbar customizer key toggles
LeanBitLab Jun 6, 2026
f87e6b1
build: bump version to v3.8.5
LeanBitLab Jun 6, 2026
d742cb9
feat: toggle dictionaries individually
LeanBitLab Jun 6, 2026
c6264c5
chore: add changelog for v3.8.5
LeanBitLab Jun 6, 2026
1f782ea
fix: split emoji search keyboard layout
LeanBitLab Jun 6, 2026
5a96d99
chore: update changelog for emoji search fix
LeanBitLab Jun 6, 2026
b6f31b3
added auto detect feature
rohanlodhi Jun 6, 2026
7131d62
changed registration flag
rohanlodhi Jun 6, 2026
03f8efd
chore: update README badges [skip ci]
github-actions[bot] Jun 7, 2026
6095b77
Update ar.txt
iBasim Jun 7, 2026
caf533b
Merge branch 'LeanBitLab:main' into main
iBasim Jun 7, 2026
13b6404
refactor: replace onnxruntime with llamacpp
LeanBitLab Jun 7, 2026
5405844
suggestion delete blacklist always. reload blacklist interface add.
LeanBitLab Jun 7, 2026
736ea03
blocked words screen add. dictionary screen integration done. setting…
LeanBitLab Jun 7, 2026
bae3869
blacklist check case-insensitive. lowercase canonicalization added. u…
LeanBitLab Jun 7, 2026
27f003f
blacklist regex support added. compiled patterns cached. compile-time…
LeanBitLab Jun 7, 2026
c53c8ea
SearchScreen remember key fix. filteredItems lambda dependency added.…
LeanBitLab Jun 7, 2026
2b17f04
Merge pull request #165 from rohanlodhi/auto-read-otp
LeanBitLab Jun 7, 2026
e4038b1
Merge pull request #168 from iBasim/main
LeanBitLab Jun 7, 2026
f91617d
fix(layout): align Arabic diacritics spacing
LeanBitLab Jun 7, 2026
74aef03
chore: update README badges [skip ci]
github-actions[bot] Jun 8, 2026
33b98cf
chore: update README badges [skip ci]
github-actions[bot] Jun 9, 2026
f646b93
chore: update README badges [skip ci]
github-actions[bot] Jun 10, 2026
ef14ac3
chore: update README badges [skip ci]
github-actions[bot] Jun 11, 2026
a4cc084
chore: update README badges [skip ci]
github-actions[bot] Jun 12, 2026
e6f1caa
Allow for reasoning models; handle structured content arrays in API r…
DXCanas Jun 12, 2026
dfaf16b
feat: add regex expander & fix dictionary crash
LeanBitLab Jun 8, 2026
da4d87f
feat(touchpad): double tap to select word & fix emoji popup preview
LeanBitLab Jun 9, 2026
28c20cb
feat(offline): add settings for custom sampling & prompt
LeanBitLab Jun 9, 2026
92b8a46
chore: update gitignore - add .env, .pi/ and remove duplicate
LeanBitLab Jun 12, 2026
007afc6
docs: add F-Droid reproducibility delay notice
LeanBitLab Jun 12, 2026
6073ba0
chore: bump version to v3.8.6 and add changelog
LeanBitLab Jun 12, 2026
4753385
fix(touchpad): always select word on double tap and update docs
LeanBitLab Jun 12, 2026
8aa21f5
feat(touchpad): implement multi-finger gestures and update docs
LeanBitLab Jun 12, 2026
45f44da
feat(touchpad): reorganize gestures for intuitive rich text editing l…
LeanBitLab Jun 12, 2026
cbf50c5
feat(touchpad): migrate gestures to 1 and 2 fingers
LeanBitLab Jun 12, 2026
4a9672a
docs: update features for llama.cpp migration
LeanBitLab Jun 12, 2026
ac80271
docs: note model-dependent accuracy in features
LeanBitLab Jun 12, 2026
36e5204
fix(touchpad): exit touchpad mode when opening clipboard or emoji
LeanBitLab Jun 12, 2026
88be2c9
perf(offline): optimize proofreading latency and load times
LeanBitLab Jun 12, 2026
ef19784
fix(offline): improve GGUF prompt formatting and output cleaning
LeanBitLab Jun 12, 2026
05fb5b9
fix(offline): truncate model output at template markers and add nativ…
LeanBitLab Jun 12, 2026
7877afb
fix(offline): implement dynamic target-language-specific few-shot exa…
LeanBitLab Jun 12, 2026
ba7ad8f
feat(expander): immediate expand & fix revert
LeanBitLab Jun 12, 2026
bd0da6a
feat: hold toolbar arrow keys to auto-repeat
LeanBitLab Jun 12, 2026
08187e7
chore: update README badges [skip ci]
github-actions[bot] Jun 13, 2026
454494b
chore: update README badges [skip ci]
github-actions[bot] Jun 14, 2026
0767b46
chore: update README badges [skip ci]
github-actions[bot] Jun 15, 2026
bb4bf8f
feat: add toggle for insecure AI connections
LeanBitLab Jun 15, 2026
3f7a4c4
Merge pull request #174 from DXCanas/allow-reasoning-models
LeanBitLab Jun 15, 2026
9b7cb2e
feat: add selective backup and restore
LeanBitLab Jun 15, 2026
7cf14c6
fix: allow same word with different shortcuts
LeanBitLab Jun 15, 2026
97802ea
feat: strip spaces before punctuation marks
LeanBitLab Jun 15, 2026
a2a6f28
chore: update README badges [skip ci]
github-actions[bot] Jun 16, 2026
95372e4
chore: update README badges [skip ci]
github-actions[bot] Jun 17, 2026
1e5a8ac
chore: update README badges [skip ci]
github-actions[bot] Jun 18, 2026
26fe524
chore: update README badges [skip ci]
github-actions[bot] Jun 19, 2026
17f541d
Change default popup key on letter ا in Persian language
nugraha-abd Jun 19, 2026
3def612
chore: update README badges [skip ci]
github-actions[bot] Jun 20, 2026
f4dce88
Merge pull request #182 from nugraha-abd/persian-default-popup
LeanBitLab Jun 20, 2026
15c903c
feat: add handwriting input support
LeanBitLab Jun 15, 2026
abd247e
docs: update 3.8.6 changelog
LeanBitLab Jun 15, 2026
dafb659
fix: use wildcard mime type for file picker to avoid waydroid crash
LeanBitLab Jun 15, 2026
66a1fdd
fix: clear code cache directory on plugin import/remove
LeanBitLab Jun 15, 2026
096a7a5
chore: add MD5 hash and size logging for loaded plugin
LeanBitLab Jun 15, 2026
751b0c6
feat(handwriting): fix crash and dynamic model downloading
LeanBitLab Jun 16, 2026
c41288a
feat: fix handwriting layout, theming and logic
LeanBitLab Jun 16, 2026
714d679
style: change handwriting toolbar icon color to white
LeanBitLab Jun 16, 2026
57f47cb
feat: show shortcut overlay on handwriting canvas when plugin missing
LeanBitLab Jun 16, 2026
7b04398
fix(ai): resolve offline custom key token loss
LeanBitLab Jun 20, 2026
d14cb17
feat(handwriting): add plugin downloader and refine blacklist
LeanBitLab Jun 20, 2026
5835d63
build: limit abi filters to arm64-v8a
LeanBitLab Jun 20, 2026
3fc71c9
docs: document handwriting and gguf features
LeanBitLab Jun 20, 2026
47ad2e2
Merge upstream LeanType v3.8.6 (handwriting, llama.cpp/GGUF, touchpad…
AsafMah Jun 20, 2026
baf42cd
chore(release): bump to 3.10.0 (4000) + changelog
AsafMah Jun 21, 2026
ce86673
fix(handwriting): don't cancel active keys when hiding inactive handw…
AsafMah Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/workflows/update-badges.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Update README Badges

on:
schedule:
- cron: '0 0 * * *' # Midnight UTC
workflow_dispatch:

permissions:
contents: write

jobs:
update-badges:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Fetch GitHub stats
id: stats
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REPO="LeanBitLab/HeliboardL"

# Latest version
VERSION=$(gh api repos/$REPO/releases/latest --jq '.tag_name' | sed 's/^v//' 2>/dev/null || echo "N/A")
echo "version=$VERSION" >> $GITHUB_OUTPUT

# Total downloads
DOWNLOADS=$(gh api repos/$REPO/releases --jq '[.[].assets[]?.download_count] | add // 0' 2>/dev/null || echo "0")
echo "downloads=$DOWNLOADS" >> $GITHUB_OUTPUT

# Stars
STARS=$(gh api repos/$REPO --jq '.stargazers_count' 2>/dev/null || echo "0")
echo "stars=$STARS" >> $GITHUB_OUTPUT

- name: Generate badge SVGs
env:
VERSION: ${{ steps.stats.outputs.version }}
DOWNLOADS: ${{ steps.stats.outputs.downloads }}
STARS: ${{ steps.stats.outputs.stars }}
run: |
mkdir -p docs/badges

# Format numbers with commas
DOWNLOADS_FMT=$(printf "%'d" "$DOWNLOADS" 2>/dev/null || echo "$DOWNLOADS")
STARS_FMT=$(printf "%'d" "$STARS" 2>/dev/null || echo "$STARS")

# Download version badge
cat > docs/badges/download.svg << EOF
<svg xmlns="http://www.w3.org/2000/svg" width="94" height="28" viewBox="0 0 94 28"><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="94" height="28" rx="4" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="50" height="28" fill="#555"/><rect x="50" width="44" height="28" fill="#7C4DFF"/><rect width="94" height="28" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11"><text x="25" y="19" fill="#010101" fill-opacity=".3">Version</text><text x="25" y="18">Version</text><text x="72" y="19" fill="#010101" fill-opacity=".3">v${VERSION}</text><text x="72" y="18">v${VERSION}</text></g></svg>
EOF

# Downloads count badge
cat > docs/badges/downloads.svg << EOF
<svg xmlns="http://www.w3.org/2000/svg" width="105" height="28" viewBox="0 0 105 28"><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="105" height="28" rx="4" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="64" height="28" fill="#555"/><rect x="64" width="41" height="28" fill="#7C4DFF"/><rect width="105" height="28" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11"><text x="32" y="19" fill="#010101" fill-opacity=".3">Downloads</text><text x="32" y="18">Downloads</text><text x="84.5" y="19" fill="#010101" fill-opacity=".3">${DOWNLOADS_FMT}</text><text x="84.5" y="18">${DOWNLOADS_FMT}</text></g></svg>
EOF

# Stars badge
cat > docs/badges/stars.svg << EOF
<svg xmlns="http://www.w3.org/2000/svg" width="72" height="28" viewBox="0 0 72 28"><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="72" height="28" rx="4" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="38" height="28" fill="#555"/><rect x="38" width="34" height="28" fill="#7C4DFF"/><rect width="72" height="28" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11"><text x="19" y="19" fill="#010101" fill-opacity=".3">Stars</text><text x="19" y="18">Stars</text><text x="55" y="19" fill="#010101" fill-opacity=".3">${STARS_FMT}</text><text x="55" y="18">${STARS_FMT}</text></g></svg>
EOF

echo "Generated: v$VERSION | $DOWNLOADS_FMT downloads | $STARS_FMT stars"

- name: Update README badge URLs
run: |
# Replace shields.io URLs with local badge paths
sed -i 's|https://img.shields.io/github/v/release/LeanBitLab/HeliboardL?label=Download\&style=for-the-badge\&color=7C4DFF|docs/badges/download.svg|g' README.md
sed -i 's|https://img.shields.io/github/downloads/LeanBitLab/HeliboardL/total?style=for-the-badge\&color=7C4DFF\&label=Downloads|docs/badges/downloads.svg|g' README.md
sed -i 's|https://img.shields.io/github/stars/LeanBitLab/HeliboardL?style=for-the-badge\&color=7C4DFF|docs/badges/stars.svg|g' README.md

- name: Commit changes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add docs/badges/ README.md
git diff --staged --quiet || git commit -m "chore: update README badges [skip ci]"
git push
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,8 @@ docs/superpowers/
.agents
.kilo/
.antigravitycli/

.env

# AI agent config (personal, not shared)
.pi/
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,30 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

## [3.10.0] - 2026-06-20

### Added
- **Handwriting input** (Standard builds) — write characters on a recognition canvas using a
downloadable plugin, with a dedicated bottom-row layout and a toolbar key.
- **Auto-read OTP from SMS** — a one-time code from an incoming SMS is offered in the suggestion
strip while the keyboard is open; tap to insert. Uses a runtime, opt-in SMS permission.
- **Regex shortcuts in Text Expander** — expansion triggers can be matched by regular expression.

### Changed
- **Offline AI backend switched from ONNX Runtime to llama.cpp (GGUF).** The Offline build now
loads compact quantized **GGUF** models on-device with configurable sampling
(temperature / top-p / top-k / min-p); it now requires Android 8 (API 26).
- **Touchpad gestures reworked** into a fuller one-/two-finger suite (word select, word-by-word
navigation, space, copy/paste, cut/select-all, undo/redo, hold-to-backspace). Single-finger
double-tap now **selects the word** (previously deleted the selection).
- Release builds now target the **arm64-v8a** ABI only.

### Upstream
- Merged **LeanBitLab/LeanType v3.8.6** (from v3.8.3) — the source of the handwriting,
llama.cpp/GGUF, touchpad-gesture, and SMS-OTP changes above. Fork identity (LeanTypeDual, distinct
`applicationId`, two-thumb typing, the Gemini standard-AI layer, and the privacy tiers) is
preserved.

## [3.9.1] - 2026-06-11

### Fixed
Expand Down
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ Type with **both thumbs gliding at the same time**: LeanTypeDual aggregates mult
### On top of that — LeanType's AI layer and quality-of-life features

- **[🤖 Multi-Provider AI](docs/FEATURES.md#supported-ai-providers)** - Proofread using **Gemini**, **Groq** (Llama 3, Mixtral), or **OpenAI-compatible** providers, with dynamic fetching of the latest models.
- **[🛡️ Offline AI](docs/FEATURES.md#5-offline-proofreading-privacy-focused)** - Private, on-device proofreading and translation using ONNX models (Offline build only).
- **[🛡️ Offline AI (GGUF)](docs/FEATURES.md#5-offline-proofreading-privacy-focused)** - Private, on-device proofreading and translation using local **GGUF models** powered by `llama.cpp` (Offline build only).
- **🌐 AI Translation** - Translate selected text using your chosen provider, with a separate model selector.
- **[✍️ Handwriting Input](docs/FEATURES.md#8-handwriting-input)** - Draw characters directly on a handwriting recognition canvas (Standard version, requires [Leantype-Handwriting-Plugin](https://github.com/LeanBitLab/Leantype-Handwriting-Plugin)).
- **[🧠 Custom AI Keys](docs/FEATURES.md#4-custom-ai-keys--keywords)** - Assign custom prompts, personas (#editor, #proofread), and labels/tags (themed capsules) to 10 customizable toolbar keys.
- **📝 Text Expander** - Shortcut → expansion with dynamic placeholders (`%clipboard%`, `%day%`, `%time12%`, `%cursor%`, lists), backspace-to-revert, and a guide.
- **📝 Text Expander** - Shortcut → expansion with dynamic placeholders (`%clipboard%`, `%day%`, `%time12%`, `%cursor%`, lists), regex shortcuts, backspace-to-revert, and a guide.
- **🧠 Smarter learned words** - *graduated trust* keeps a just-learned word below real-dictionary suggestions until you've used it a few times (no premature autocorrect to half-typed words); flag unknown words to **Add** or **Block** them via a Blocklist screen.
- **↩️ Undo word** - a toolbar key that reverts the last committed word back to its suggestion alternatives.
- **🗂️ Per-dictionary control** - enable or disable individual built-in and custom dictionaries.
Expand All @@ -38,7 +39,7 @@ Type with **both thumbs gliding at the same time**: LeanTypeDual aggregates mult
- **📸 Screenshot Suggestion & Clipboard** - Recently-taken screenshots are offered in the suggestion strip and saved to clipboard history.
- **🔎 Emoji Search** - Search emojis by name. *Requires loading an Emoji Dictionary.*
- **⚙️ Enhanced Customization** - Force auto-capitalization, fine-grained haptics, distinct incognito icon, reorganized settings, and more.
- **🔒 Privacy Choices** - Choose **Standard** (opt-in AI), **Offline** (network hard-disabled, offline model), or **Offline Lite** (no AI, ~20 MB).
- **🔒 Privacy Choices** - Choose **Standard** (opt-in AI, handwriting), **Offline** (network hard-disabled, offline GGUF model), or **Offline Lite** (no AI, ~20 MB).



Expand Down Expand Up @@ -73,20 +74,22 @@ Type with **both thumbs gliding at the same time**: LeanTypeDual aggregates mult
</tr>
</table>

> **⚠️ Note:** F-Droid releases might be delayed or stuck again due to reproducibility verification issues. For the latest version, use GitHub Releases or Obtainium.

### 📦 Choose Your Version

#### 1. Standard Version (`-standard-release.apk`)
* **Features:** Full suite including **AI Proofreading**, **AI Translation**, and **Gesture Library Downloader**.
* **Permissions:** Request `INTERNET` permission (used *only* when you explicitly use AI features).
* **Setup:** Use the built-in downloader for Gesture Typing. Configure AI keys in Settings.
* **Features:** Full suite including **AI Proofreading**, **AI Translation**, **Handwriting Input**, and **Gesture Library Downloader**.
* **Permissions:** Request `INTERNET` permission (used *only* when you explicitly use AI features, download plugins, or update libraries).
* **Setup:** Use the built-in downloader for Gesture Typing and Handwriting Input. Configure AI keys in Settings.

#### 2. Offline Version (`-offline-release.apk`)
* **Features:** All UI/UX enhancements and **Offline Neural Proofreading** (ONNX).
* **Features:** All UI/UX enhancements and **Offline Neural Proofreading** (via `llama.cpp` using local **GGUF models**).
* **Permissions:** **NO INTERNET PERMISSION**. Guaranteed at OS level.
* **Best For:** Privacy purists.
* **Manual Setup Required:**
* **Gesture Typing:** [Download library manually](https://github.com/erkserkserks/openboard/tree/46fdf2b550035ca69299ce312fa158e7ade36967/app/src/main/jniLibs) and load via *Settings > Gesture typing*.
* **Offline AI:** Download ONNX models and load via *Settings > AI Integration*. 👉 **[See Offline Setup Instructions](docs/FEATURES.md#3-offline-proofreading-privacy-focused)**
* **Offline AI:** Download GGUF models and load via *Settings > Advanced > GGUF Model (.gguf)*. 👉 **[See Offline Setup Instructions](docs/FEATURES.md#5-offline-proofreading-privacy-focused)**

#### 3. Offline Lite Version (`-offlinelite-release.apk`)
* **Features:** All UI/UX enhancements but **NO AI FEATURES**.
Expand Down
30 changes: 21 additions & 9 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@ if (keystorePropertiesFile.exists()) {
}

android {
compileSdk = 35
compileSdk = 36

defaultConfig {
applicationId = "com.asafmah.leantypedual"
minSdk = 21
targetSdk = 35
versionCode = 3910
versionName = "3.9.1"
versionCode = 4000
versionName = "3.10.0"

proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")

ndk {
abiFilters.addAll(arrayOf("armeabi-v7a", "arm64-v8a"))
abiFilters.addAll(arrayOf("arm64-v8a"))
}
}

// ONNX Runtime is used instead of llama.cpp native build

flavorDimensions += "privacy"
productFlavors {
create("standard") {
Expand All @@ -45,6 +43,7 @@ android {
create("offline") {
dimension = "privacy"
applicationIdSuffix = ".offline"
minSdk = 26
}
create("offlinelite") {
dimension = "privacy"
Expand Down Expand Up @@ -141,7 +140,7 @@ android {
path = File("src/main/jni/Android.mk")
}
}
// ndkVersion = "28.0.13004108"
ndkVersion = "28.0.13004108"

packaging {
jniLibs {
Expand Down Expand Up @@ -235,8 +234,21 @@ dependencies {
"standardOptimisedImplementation"("androidx.security:security-crypto:1.1.0-alpha06")

// local llm proofreading (offline)
// ONNX Runtime for T5 encoder-decoder grammar models
"offlineImplementation"("com.microsoft.onnxruntime:onnxruntime-android:1.17.3")
"offlineImplementation"("io.github.ljcamargo:llamacpp-kotlin:0.4.0")

// Force 16 KB page-aligned version of graphics-path
implementation("androidx.graphics:graphics-path:1.1.0")

// WorkManager — required by ML Kit Digital Ink plugin (loaded via DexClassLoader).
// ML Kit internally calls WorkManager.getInstance(context) using the host app context,
// so the host app must have WorkManagerInitializer registered in its manifest.
implementation("androidx.work:work-runtime-ktx:2.10.1")

// ML Kit Digital Ink Recognition — required by the handwriting plugin.
// ML Kit's internal asset manager and native library loader use the host app context,
// so the host app must compile and include the client library resources/libraries.
"standardImplementation"("com.google.mlkit:digital-ink-recognition:19.0.0")
"standardOptimisedImplementation"("com.google.mlkit:digital-ink-recognition:19.0.0")

// test
testImplementation(kotlin("test"))
Expand Down
3 changes: 0 additions & 3 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
# Keep java-llama.cpp classes
-keep class de.kherud.llama.** { *; }

# ONNX Runtime configurations
-dontwarn com.google.protobuf.**
-keep class ai.onnxruntime.** { *; }

# Fix correct service name
-keep class helium314.keyboard.latin.utils.ProofreadService { *; }
Expand Down
34 changes: 33 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">


<uses-sdk tools:overrideLibrary="androidx.graphics.path,com.google.mlkit.vision.digitalink.recognition,com.google.mlkit.digitalink.common" />

<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- Optional: only requested at runtime when the user enables the "Auto-read OTP" feature. -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Expand All @@ -27,6 +29,8 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
android:allowBackup="false"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true"
tools:remove="android:appComponentFactory"
tools:targetApi="p">

Expand Down Expand Up @@ -122,6 +126,34 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
android:resource="@xml/provider_paths" />
</provider>

<!-- Disable WorkManager auto-initializer; App implements Configuration.Provider instead.
Required for ML Kit Digital Ink plugin loaded via DexClassLoader. -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>

<!-- Service for ML Kit component discovery.
Since the ML Kit libraries are loaded dynamically from the plugin APK,
we must register these in the host app manifest so ML Kit can find them. -->
<service
android:name="com.google.mlkit.common.internal.MlKitComponentDiscoveryService"
android:directBootAware="true"
android:exported="false">
<meta-data
android:name="com.google.firebase.components:com.google.mlkit.common.internal.CommonComponentRegistrar"
android:value="com.google.firebase.components.ComponentRegistrar" />
<meta-data
android:name="com.google.firebase.components:com.google.mlkit.vision.digitalink.internal.DigitalInkRecognitionRegistrar"
android:value="com.google.firebase.components.ComponentRegistrar" />
</service>

</application>

<queries>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
[
{ "label": "alpha", "width": 0.15 },
{ "label": "clear_handwriting", "width": 0.15 },
{ "label": "space", "width": -1 },
{ "label": "delete", "width": 0.15 }
]
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
[
{ "label": "alpha", "width": 0.15 },
{ "label": "clear_handwriting", "width": 0.15 },
{ "label": "space", "width": -1 },
{ "label": "delete", "width": 0.15 },
{ "label": "action", "width": 0.15 }
]
]
6 changes: 3 additions & 3 deletions app/src/main/assets/locale_key_texts/ar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
ه ﻫ|ه‍
ج چ
ش ڜ
ي ئ ى
ي ى ئ
ب پ
ل ﻻ|لا ﻷ|لأ ﻹ|لإ ﻵ|لآ
ا !fixedOrder!5 آ ء أ إ ٱ
ا !fixedOrder!5 أ ٱ إ آ ء
ك گ ک
ى ئ
ز ژ
و ؤ
punctuation !fixedOrder!7 ٕ|ٕ ٔ|ٔ ْ|ْ ٍ ٌ|ٌ ً ّ|ّ ٖ|ٖ ٰ ٓ|ٓ ِ|ِ ُ|ُ َ|َ ـــ|ـ
punctuation !fixedOrder!7 ّ◌|ّ ْ◌|ْ َ◌|َ ِ◌|ِ ُ◌|ُ ٍ◌ً◌ٌ◌|ٌ ٓ◌|ٓ ٰ◌ٕ◌|ٕ ٔ◌|ٔ ٖ◌|ٖ ـــ|ـ
« „ “ ”
» ‚ ‘ ’ ‹ ›

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/assets/locale_key_texts/fa.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[popup_keys]
ه ﻫ|ه‍ هٔ ة
ی ئ ي ﯨ|ى
ا !fixedOrder!5 ٱ ء آ أ إ
ا !fixedOrder!5 آ ء ٱ أ إ
ت ة
ک ك
و ؤ
Expand Down
Loading
Loading