Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
282 commits
Select commit Hold shift + click to select a range
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
f86a07c
chore: update README badges [skip ci]
github-actions[bot] Jun 21, 2026
bb93b6c
chore: update README badges [skip ci]
github-actions[bot] Jun 22, 2026
28b1c37
fix(handwriting): avoid cancelling active keys when hidden
AsafMah Jun 22, 2026
d5d10ac
build: update config, proguard rules, and blacklist parsing
LeanBitLab Jun 22, 2026
82033c7
Merge pull request #194 from AsafMah/fix/upstream-handwriting-shift-r…
LeanBitLab Jun 22, 2026
ec1de5f
feat: tune double-tap shift timing and keep llamacpp proguard
LeanBitLab Jun 22, 2026
c8b9d7b
build: remove standardOptimised flavor
LeanBitLab Jun 22, 2026
d645a2a
fix: prevent handwriting suggestions from hiding
LeanBitLab Jun 22, 2026
f2b770f
chore: update README badges [skip ci]
github-actions[bot] Jun 23, 2026
6a60092
fix(toolbar): restore close/search on clipboard
LeanBitLab Jun 23, 2026
c059da4
fix(settings): add label for clipboard_search key
LeanBitLab Jun 23, 2026
264956e
feat(settings): allow deleting handwriting model
LeanBitLab Jun 23, 2026
776156e
feat(dict): add dynamic dictionary downloader
LeanBitLab Jun 23, 2026
ec8839b
feat(dict): allow uninstalling downloaded dicts
LeanBitLab Jun 23, 2026
fc02d43
feat(dict): improve dynamic downloading flow
LeanBitLab Jun 23, 2026
422a705
fix: keep number row digits when keyboard is shifted
mvanhorn Jun 23, 2026
6a04287
feat(dict): exclude non-en-US dictionaries from standard flavor assets
LeanBitLab Jun 23, 2026
b31077a
feat(dict): show download button on toolbar if layout dictionary is n…
LeanBitLab Jun 23, 2026
62f4deb
fix: do not show disabled additional subtypes in dict settings list
LeanBitLab Jun 23, 2026
216d150
chore: add v3.8.7 and v3.8.8 changelogs
LeanBitLab Jun 23, 2026
a84f4ae
fix: prevent WindowManager$BadTokenException in IME overlay dialog
LeanBitLab Jun 23, 2026
b49f677
Merge pull request #199 from mvanhorn/fix/180-number-row-shift-symbols
LeanBitLab Jun 23, 2026
a0eda87
fix: only update split toolbar emoji recents when view is visible
LeanBitLab Jun 23, 2026
233066f
feat(emoji): close search on dictionary download
LeanBitLab Jun 23, 2026
37c0bb5
feat(emoji): show download button in split toolbar
LeanBitLab Jun 23, 2026
6c427e5
chore: update changelog for 3.8.8
LeanBitLab Jun 23, 2026
8531a2f
chore: bump version to 3.8.8
LeanBitLab Jun 23, 2026
f19b0e4
feat(handwriting): add download button to plugin required overlay
LeanBitLab Jun 23, 2026
26b7cf5
chore: add handwriting plugin downloader to 3.8.8 changelog
LeanBitLab Jun 23, 2026
07005cb
docs: temporarily hide F-Droid badge from README
LeanBitLab Jun 23, 2026
1dd8a98
docs: remove F-Droid column from table to fix spacing
LeanBitLab Jun 23, 2026
9929d9d
docs: move download section above screenshots in README
LeanBitLab Jun 23, 2026
44987c1
docs: remove fork AI feature description line from README
LeanBitLab Jun 23, 2026
3d0f510
docs: add Dynamic Downloader to README features
LeanBitLab Jun 23, 2026
f88c12c
docs: add Selective Backup, Blacklist, and OTP features to README
LeanBitLab Jun 23, 2026
1c66c91
docs: sort features by significance in README
LeanBitLab Jun 23, 2026
e2763bf
chore: update README badges [skip ci]
github-actions[bot] Jun 24, 2026
82cdae8
fix: make entire suggestion word a delete target on long-press
LeanBitLab Jun 24, 2026
0037701
feat: add back armeabi-v7a to ABI filters
LeanBitLab Jun 24, 2026
71aa6f5
chore: update README badges [skip ci]
github-actions[bot] Jun 25, 2026
722de8e
chore: update README badges [skip ci]
github-actions[bot] Jun 26, 2026
0b87efc
chore: update README badges [skip ci]
github-actions[bot] Jun 27, 2026
a297069
feat: split standard flavor and enable predictions
LeanBitLab Jun 25, 2026
d2efb18
chore: add active suggestions to v3.8.9 changelog
LeanBitLab Jun 25, 2026
c9ee188
docs: update v3.8.9 changelog with popup contrast fix
LeanBitLab Jun 25, 2026
cc57457
ci: integrate docs release notes script into workflow
LeanBitLab Jun 25, 2026
91f2b47
feat(dict): support dynamic bigrams via space-separated personal dict…
LeanBitLab Jun 25, 2026
2deef97
feat(settings): support shortcut-specific prefixes for text expander
LeanBitLab Jun 25, 2026
ffe88b1
docs(changelog): document dynamic bigrams and text expander shortcut-…
LeanBitLab Jun 25, 2026
227decb
ci(workflow): automate github release creation on tag push
LeanBitLab Jun 25, 2026
0b7dd20
fix(suggestions): color active prediction suggestion bright
LeanBitLab Jun 25, 2026
7512efa
fix: remove fallback suggestions in split mode
LeanBitLab Jun 27, 2026
36f407e
fix: toggle downloaded dicts & resolve path clash
LeanBitLab Jun 27, 2026
7066cd9
style: polish dictionary screen UI & theme support
LeanBitLab Jun 27, 2026
e636527
style: uniform size for dictionary screen icons
LeanBitLab Jun 27, 2026
6b8c963
style: show clean badge label for downloaded dict
LeanBitLab Jun 27, 2026
01e0b5a
fix: support parent language dictionary fallback
LeanBitLab Jun 27, 2026
e056055
style: support downloaded emoji dict toggling
LeanBitLab Jun 27, 2026
cf157c7
style: unify dictionary toggling and remove buttons
LeanBitLab Jun 27, 2026
57efab5
style: skip redundant cards for disabled language variants
LeanBitLab Jun 27, 2026
d3ca828
fix: support multi-part locales download path
LeanBitLab Jun 27, 2026
1e14661
fix: persist clipboard dismiss and reduce timeout
LeanBitLab Jun 27, 2026
df868ef
feat: implement text editing mode toolbar key and overlay
LeanBitLab Jun 27, 2026
aa96847
feat: add separate Touchpad settings section and fullscreen mode
LeanBitLab Jun 27, 2026
3d8f8be
feat: add close button to touchpad view
LeanBitLab Jun 27, 2026
f3d0641
fix: correct text expander suffix matching with shortcut specific pre…
LeanBitLab Jun 27, 2026
2b764e9
style: layout prefix above shortcut in text expander dialog
LeanBitLab Jun 27, 2026
51c1225
docs: update v3.8.9 changelog in fastlane
LeanBitLab Jun 27, 2026
ab943d5
docs: update v3.8.9 release notes
LeanBitLab Jun 27, 2026
2ced601
docs: compact v3.8.9 changelog in fastlane
LeanBitLab Jun 27, 2026
8d61807
docs: update release notes python script and gitignore
LeanBitLab Jun 27, 2026
5611fcf
fix: correct keystore path in build release workflow
LeanBitLab Jun 27, 2026
49c477b
chore: update README badges [skip ci]
github-actions[bot] Jun 28, 2026
dd9c860
chore: update README badges [skip ci]
github-actions[bot] Jun 29, 2026
e9dabc9
feat: improve text edit mode keypress and layout
LeanBitLab Jun 28, 2026
69bd4b9
feat: add undo button and color variations to text edit toolbar
LeanBitLab Jun 28, 2026
7fac209
feat: add functional color shading and high contrast to text edit too…
LeanBitLab Jun 28, 2026
4ea177a
fix: use WCAG contrast ratio for dynamic theme legibility
LeanBitLab Jun 28, 2026
d19f379
fix: resolve contrast issues on other themes and key popups
LeanBitLab Jun 28, 2026
b755c3d
fix: robust downloads and keep toolbar settings visible
LeanBitLab Jun 28, 2026
6cc639b
feat: add Ko-fi support link in About settings
LeanBitLab Jun 28, 2026
2ff7085
feat: add Ko-fi button to SponsorDialog
LeanBitLab Jun 28, 2026
0ef860d
style: remove top gradient header from SponsorDialog
LeanBitLab Jun 28, 2026
34efba9
refactor: apply ponytail audit cleanups to JniUtils and ColorUtil
LeanBitLab Jun 28, 2026
5399712
refactor: delete SpacedTokens and use standard library string split
LeanBitLab Jun 28, 2026
7f16b01
perf: apply hot-path optimizations and cleanup unused paint
LeanBitLab Jun 28, 2026
d135d6b
refactor: apply handwriting and text expander cleanups
LeanBitLab Jun 28, 2026
70509d9
feat: make top close button exit handwriting mode instead of clearing
LeanBitLab Jun 28, 2026
4b34736
feat: close handwriting input view via long pressing bottom row clear…
LeanBitLab Jun 28, 2026
80efccc
fix: cancel all pointer trackers on long press handwriting exit to di…
LeanBitLab Jun 28, 2026
b13d9d2
fix: dismiss and clear all key previews when closing or canceling ong…
LeanBitLab Jun 28, 2026
734e21b
style/feat: unify visual styling and functional long-press behaviors …
LeanBitLab Jun 28, 2026
85a8939
fix: resolve NullPointerException on toolbar key setup due to prematu…
LeanBitLab Jun 28, 2026
b21ccf5
fix: clear color filter on ImageView when setting to TOOL_BAR_KEY to …
LeanBitLab Jun 28, 2026
102de7d
style: set uniform icon padding on all toolbar keys for proportional …
LeanBitLab Jun 28, 2026
708c3ff
fix: delegate intrinsic width, height and minimum dimensions in LongP…
LeanBitLab Jun 28, 2026
08f482f
style: replace blocky triangle indicator with a clean and minimal dot…
LeanBitLab Jun 28, 2026
0b6c853
style: color long-press indicator dot using the theme's native key hi…
LeanBitLab Jun 28, 2026
fc74398
style: color long-press indicator dot using the theme's accent color
LeanBitLab Jun 28, 2026
f08ad26
feat: improve text edit mode and selection
LeanBitLab Jun 29, 2026
1e131e1
feat: support selection modifier on word and page keypresses
LeanBitLab Jun 29, 2026
06f6314
feat: transition editing mode to standard parsed JSON layout
LeanBitLab Jun 29, 2026
dccf520
fix: map correct heliboard keycodes in editing layout
LeanBitLab Jun 29, 2026
ddab20d
design: redesign editing layout to 5x4 grid with premium icons
LeanBitLab Jun 29, 2026
6f3442e
feat: draw select mode key with active background highlight
LeanBitLab Jun 29, 2026
2a60273
design: use uniform text labels for edit layout commands to avoid emo…
LeanBitLab Jun 29, 2026
24e651d
fix: resolve abc and backspace button functions on editing layout
LeanBitLab Jun 29, 2026
a4a06a3
design: differentiate color shades of navigation and operation keys i…
LeanBitLab Jun 29, 2026
418b6b9
design: set action key type for abc, select, and delete keys in editi…
LeanBitLab Jun 29, 2026
35391bf
design: apply graduated dark shading overlays to abc, select, and del…
LeanBitLab Jun 29, 2026
e77f3ed
design: blend accent color with functional key background for premium…
LeanBitLab Jun 29, 2026
31f9da6
design: apply user mockup color scheme with dark contrast text and icons
LeanBitLab Jun 29, 2026
bc90178
design: revert custom coloring on word, document, and line jump navig…
LeanBitLab Jun 29, 2026
42729e4
feat: support custom max tokens and edit colors
LeanBitLab Jun 29, 2026
e01e751
style: make default edit mode colors theme-aware
LeanBitLab Jun 29, 2026
c0107e6
fix: resolve dictionary toggle and list bugs
LeanBitLab Jun 29, 2026
a1d866f
fix: prevent duplicate clipboard suggestion dismiss reset
LeanBitLab Jun 29, 2026
000c9ab
release: bump version to 3.9.0 and update release metadata
LeanBitLab Jun 29, 2026
c3c97cd
docs: update release notes and changelog to include missed items
LeanBitLab Jun 29, 2026
d934323
docs: add Text Editing Mode to README feature list
LeanBitLab Jun 29, 2026
e59fa54
docs: add Ko-fi donation link to README
LeanBitLab Jun 29, 2026
92ee110
chore: add Ko-fi to funding options
LeanBitLab Jun 29, 2026
357b4f2
fix: filter preloaded dicts in settings, relax autocorrect thresholds…
LeanBitLab Jun 29, 2026
4a9644c
feat: add autospace after emoji setting
LeanBitLab Jun 29, 2026
74ad138
chore: update README badges [skip ci]
github-actions[bot] Jun 30, 2026
c823abf
chore: update README badges [skip ci]
github-actions[bot] Jul 1, 2026
8ff93c9
chore: update README badges [skip ci]
github-actions[bot] Jul 2, 2026
c5787c3
feat: add toggle to disable long-press hint dots on toolbar keys
mvanhorn Jul 2, 2026
948b514
Merge pull request #224 from mvanhorn/feat/218-toolbar-longpress-hint…
LeanBitLab Jul 2, 2026
a037ef8
fix: icon style syncs with theme style. add holo/rounded text edit dr…
LeanBitLab Jul 2, 2026
18551f5
fix: add holo and rounded variants for handwriting icon
LeanBitLab Jul 2, 2026
45feaa8
chore: remove Ko-fi support option and links
LeanBitLab Jul 2, 2026
d357554
Revert "fix: add holo and rounded variants for handwriting icon"
LeanBitLab Jul 2, 2026
238e179
Revert "fix: icon style syncs with theme style. add holo/rounded text…
LeanBitLab Jul 2, 2026
a1f3d54
feat: show total blocked words count in title
LeanBitLab Jul 2, 2026
184ef70
docs: restore f-droid link in readme
LeanBitLab Jul 2, 2026
23142ff
docs: remove f-droid delay note from readme
LeanBitLab Jul 2, 2026
9f67365
chore: update README badges [skip ci]
github-actions[bot] Jul 3, 2026
58407d2
feat: add toggle to persist text edit mode
LeanBitLab Jul 2, 2026
c5721d6
feat: add pure-Java gesture typing fallback (SwipeGestureEngine)
LeanBitLab Jul 2, 2026
2d0662c
fix: resolve gesture engine ANR by releasing readLock and sleeping pe…
LeanBitLab Jul 2, 2026
6d77834
feat: make swipe gesture engine start and end keys matching forgiving…
LeanBitLab Jul 2, 2026
925b7e8
feat: make gesture typing smarter using sequence matching penalty and…
LeanBitLab Jul 2, 2026
5b458b1
perf: speed up gesture index building by bypassing heavy word propert…
LeanBitLab Jul 2, 2026
6163327
fix: resolve frequency lookup failure in fast dictionary iteration by…
LeanBitLab Jul 2, 2026
5166aa9
feat: improve gesture ranking with endpoint-weighted L2 scoring and s…
LeanBitLab Jul 2, 2026
51e57cf
perf: prune low-frequency main dictionary entries and use flat-array …
LeanBitLab Jul 2, 2026
6796257
feat: enable swipe gesture engine self-learning by indexing user hist…
LeanBitLab Jul 2, 2026
15b7951
feat: add settings toggle to select native vs fallback gesture method
LeanBitLab Jul 2, 2026
b9e1539
fix: fix false-positive gesture library active status in libraries se…
LeanBitLab Jul 2, 2026
19f0a43
style: move gesture typing method selection to top of configuration c…
LeanBitLab Jul 2, 2026
95cff44
style: put gesture input switch at top and conditionally hide method/…
LeanBitLab Jul 2, 2026
5133986
style: hide native library loader option when fallback engine is sele…
LeanBitLab Jul 2, 2026
77836f3
perf+feat: optimize gesture engine — cache charToPos, primitive sort,…
LeanBitLab Jul 2, 2026
e0fb5fe
fix: preserve manually-typed spaces before punctuation
LeanBitLab Jul 3, 2026
abb2b17
chore: bump version to 3.9.1
LeanBitLab Jul 3, 2026
fdbe750
docs: add release notes for 3.9.1 and update fastlane changelog
LeanBitLab Jul 3, 2026
bbdca24
docs: credit HeliBoard PR #2351 for pure-Java fallback engine in rele…
LeanBitLab Jul 3, 2026
ce05222
docs: note pure-Java fallback engine is experimental alpha stage
LeanBitLab Jul 3, 2026
394bb60
feat: add language layout and gesture engine selection to setup welco…
LeanBitLab Jul 3, 2026
7b31ea0
Merge upstream LeanType v3.9.1
AsafMah Jul 4, 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
30 changes: 30 additions & 0 deletions app/src/main/assets/layouts/editing/editing.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[
[
{ "code": -131, "label": "Undo", "type": "function", "width": 0.2 },
{ "code": -132, "label": "Redo", "type": "function", "width": 0.2 },
{ "code": -35, "label": "All", "type": "function", "width": 0.2 },
{ "code": -34, "label": "Word", "type": "function", "width": 0.2 },
{ "code": -201, "label": "✕", "type": "function", "width": 0.2 }
],
[
{ "code": -32, "label": "Cut", "type": "function", "width": 0.2 },
{ "code": -25, "label": "⤒", "width": 0.2 },
{ "code": -23, "label": "↑", "width": 0.2 },
{ "code": -26, "label": "⤓", "width": 0.2 },
{ "code": -7, "label": "delete", "type": "function", "width": 0.2 }
],
[
{ "code": -31, "label": "Copy", "type": "function", "width": 0.2 },
{ "code": -21, "label": "←", "width": 0.2 },
{ "code": -306, "label": "Select", "type": "function", "width": 0.2 },
{ "code": -22, "label": "→", "width": 0.2 },
{ "code": -10015, "label": "«", "width": 0.2 }
],
[
{ "code": -33, "label": "Paste", "type": "function", "width": 0.2 },
{ "code": -27, "label": "⇱", "width": 0.2 },
{ "code": -24, "label": "↓", "width": 0.2 },
{ "code": -28, "label": "⇲", "width": 0.2 },
{ "code": -10016, "label": "»", "width": 0.2 }
]
]
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,37 @@ public GetNextWordPropertyResult getNextWordProperty(final int token) {
getWordProperty(word, isBeginningOfSentence[0]), nextToken);
}

// ponytail: allocation-free container for fast dict iteration
public static class WordAndFrequency {
public final String mWord;
public final int mFrequency;
public WordAndFrequency(String word, int frequency) {
mWord = word;
mFrequency = frequency;
}
}

// ponytail: allocation-free result container for fast dict iteration
public static class GetNextWordAndFrequencyResult {
public final WordAndFrequency mWordAndFrequency;
public final int mNextToken;
public GetNextWordAndFrequencyResult(WordAndFrequency wordAndFrequency, int nextToken) {
mWordAndFrequency = wordAndFrequency;
mNextToken = nextToken;
}
}

// ponytail: fast word iteration that avoids fetching heavy shortcut/ngram metadata
public GetNextWordAndFrequencyResult getNextWordAndFrequency(final int token) {
final int[] codePoints = new int[DICTIONARY_MAX_WORD_LENGTH];
final boolean[] isBeginningOfSentence = new boolean[1];
final int nextToken = getNextWordNative(mNativeDict, token, codePoints,
isBeginningOfSentence);
final String word = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
final int probability = getFrequency(word);
return new GetNextWordAndFrequencyResult(new WordAndFrequency(word, probability), nextToken);
}

// Add a unigram entry to binary dictionary with unigram attributes in native code.
public boolean addUnigramEntry(final String word, final int probability,
final String shortcutTarget, final int shortcutProbability,
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/helium314/keyboard/keyboard/Key.java
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,7 @@ public KeyParams(
// action flags don't need to be specified, they can be deduced from the key
if (mCode == Constants.CODE_SPACE
|| mCode == KeyCode.LANGUAGE_SWITCH
|| mCode == KeyCode.CLEAR_HANDWRITING
|| (mCode == KeyCode.SYMBOL_ALPHA && !params.mId.isAlphabetKeyboard()))
actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
if (mCode <= Constants.CODE_SPACE && mCode != KeyCode.MULTIPLE_CODE_POINTS && mIconName == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,39 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
}

override fun onCodeInput(primaryCode: Int, x: Int, y: Int, isKeyRepeat: Boolean) {
val isArrow = primaryCode == KeyCode.ARROW_LEFT || primaryCode == KeyCode.ARROW_RIGHT || primaryCode == KeyCode.ARROW_UP || primaryCode == KeyCode.ARROW_DOWN
if (isArrow) {
val isSelecting = keyboardSwitcher.keyboard?.mId?.isAlphabetShifted == true || sPersistentSelectionModeActive
if (isSelecting) {
val androidKeyCode = when (primaryCode) {
KeyCode.ARROW_LEFT -> KeyEvent.KEYCODE_DPAD_LEFT
KeyCode.ARROW_RIGHT -> KeyEvent.KEYCODE_DPAD_RIGHT
KeyCode.ARROW_UP -> KeyEvent.KEYCODE_DPAD_UP
KeyCode.ARROW_DOWN -> KeyEvent.KEYCODE_DPAD_DOWN
else -> 0
}
if (androidKeyCode != 0) {
val eventTime = android.os.SystemClock.uptimeMillis()
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0))
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, androidKeyCode, 0, KeyEvent.META_SHIFT_ON))
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, androidKeyCode, 0, KeyEvent.META_SHIFT_ON))
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0))
}
return
}
}
when (primaryCode) {
KeyCode.TOGGLE_SELECTION_MODE -> {
sPersistentSelectionModeActive = !sPersistentSelectionModeActive
keyboardSwitcher.mainKeyboardView?.invalidateAllKeys()
keyboardSwitcher.suggestionStripView?.refreshToolbarButtonsActivation()
return
}
KeyCode.ALPHA -> {
sPersistentTextEditModeActive = false
sPersistentSelectionModeActive = false
keyboardSwitcher.hideTextEditView()
}
KeyCode.HANDWRITING -> {
if (keyboardSwitcher.isHandwritingShowing) {
keyboardSwitcher.setAlphabetKeyboard()
Expand Down Expand Up @@ -167,12 +199,7 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
if (sPersistentTextEditModeActive) {
PointerTracker.sPersistentTouchpadModeActive = false
keyboardSwitcher.hideTouchpadView()

val textEditView = keyboardSwitcher.textEditView
if (textEditView != null) {
setupTextEditListener(textEditView)
keyboardSwitcher.showTextEditView()
}
keyboardSwitcher.showTextEditView()
} else {
keyboardSwitcher.hideTextEditView()
}
Expand All @@ -188,17 +215,21 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
}
val mkv = keyboardSwitcher.mainKeyboardView

val isEditingNav = primaryCode == KeyCode.WORD_LEFT || primaryCode == KeyCode.WORD_RIGHT
|| primaryCode == KeyCode.MOVE_START_OF_PAGE || primaryCode == KeyCode.MOVE_END_OF_PAGE
|| primaryCode == KeyCode.MOVE_START_OF_LINE || primaryCode == KeyCode.MOVE_END_OF_LINE
|| primaryCode == KeyCode.PAGE_UP || primaryCode == KeyCode.PAGE_DOWN
val eventMetaState = if (isEditingNav && (keyboardSwitcher.keyboard?.mId?.isAlphabetShifted == true || sPersistentSelectionModeActive)) {
metaState or KeyEvent.META_SHIFT_ON
} else {
metaState
}

// checking if the character is a combining accent
val event = if (primaryCode in combiningRange) { // todo: should this be done later, maybe in inputLogic?
Event.createSoftwareDeadEvent(primaryCode, 0, metaState, mkv.getKeyX(x), mkv.getKeyY(y), null)
Event.createSoftwareDeadEvent(primaryCode, 0, eventMetaState, mkv.getKeyX(x), mkv.getKeyY(y), null)
} else {
// todo:
// setting meta shift should only be done for arrow and similar cursor movement keys
// should only be enabled once it works more reliably (currently depends on app for some reason)
// if (mkv.keyboard?.mId?.isAlphabetShiftedManually == true)
// Event.createSoftwareKeypressEvent(primaryCode, metaState or KeyEvent.META_SHIFT_ON, mkv.getKeyX(x), mkv.getKeyY(y), isKeyRepeat)
// else Event.createSoftwareKeypressEvent(primaryCode, metaState, mkv.getKeyX(x), mkv.getKeyY(y), isKeyRepeat)
Event.createSoftwareKeypressEvent(primaryCode, metaState, mkv.getKeyX(x), mkv.getKeyY(y), isKeyRepeat)
Event.createSoftwareKeypressEvent(primaryCode, eventMetaState, mkv.getKeyX(x), mkv.getKeyY(y), isKeyRepeat)
}
latinIME.onEvent(event)
metaAfterCodeInput(primaryCode)
Expand Down Expand Up @@ -360,6 +391,21 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
val rtl = RichInputMethodManager.getInstance().currentSubtype.isRtlSubtype
val steps = if (rtl) -rawSteps else rawSteps

val isSelecting = keyboardSwitcher.keyboard?.mId?.isAlphabetShifted == true || sPersistentSelectionModeActive
if (isSelecting) {
val code = if (steps < 0) {
gestureMoveBackHaptics()
if (rtl) KeyCode.ARROW_RIGHT else KeyCode.ARROW_LEFT
} else {
gestureMoveForwardHaptics(true)
if (rtl) KeyCode.ARROW_LEFT else KeyCode.ARROW_RIGHT
}
repeat(abs(steps)) {
onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false)
}
return true
}

// Web editors (Chromium, Firefox, etc.) handle direct setSelection badly during fast swipes,
// often resulting in focus loss, caret hiding, or composition desynchronization.
// Fall back to sending simulated arrow keys, which is fast, asynchronous, and robust.
Expand Down Expand Up @@ -670,43 +716,13 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
})
}

fun setupTextEditListener(textEditView: TextEditView) {
textEditView.setTextEditListener(object : TextEditView.TextEditListener {
override fun onCursorMove(keyCode: Int, isSelecting: Boolean) {
if (isSelecting) {
val androidKeyCode = when (keyCode) {
KeyCode.ARROW_UP -> KeyEvent.KEYCODE_DPAD_UP
KeyCode.ARROW_DOWN -> KeyEvent.KEYCODE_DPAD_DOWN
KeyCode.ARROW_LEFT -> KeyEvent.KEYCODE_DPAD_LEFT
KeyCode.ARROW_RIGHT -> KeyEvent.KEYCODE_DPAD_RIGHT
else -> 0
}
if (androidKeyCode != 0) {
val eventTime = android.os.SystemClock.uptimeMillis()
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0))
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, androidKeyCode, 0, KeyEvent.META_SHIFT_ON))
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, androidKeyCode, 0, KeyEvent.META_SHIFT_ON))
connection.sendKeyEvent(KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0))
}
} else {
onCodeInput(keyCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false)
}
}

override fun onCodeInput(keyCode: Int) {
onCodeInput(keyCode, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false)
}

override fun onClose() {
sPersistentTextEditModeActive = false
keyboardSwitcher.hideTextEditView()
}
})
}

companion object {
@JvmField
var sPersistentTextEditModeActive = false
@JvmField
var sPersistentSelectionModeActive = false
private enum class MetaPressState {
UNSET, // default state, not active
SET, // enabled without onPressKey (e.g. in popup)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public final class KeyboardId {
public static final int ELEMENT_EMOJI_BOTTOM_ROW = 29;
public static final int ELEMENT_CLIPBOARD_BOTTOM_ROW = 30;
public static final int ELEMENT_HANDWRITING_BOTTOM_ROW = 31;
public static final int ELEMENT_TEXT_EDIT = 32;

public final RichInputMethodSubtype mSubtype;
public final int mWidth;
Expand Down Expand Up @@ -294,6 +295,7 @@ public static String elementIdToName(final int elementId) {
case ELEMENT_EMOJI_BOTTOM_ROW -> "emojiBottomRow";
case ELEMENT_CLIPBOARD_BOTTOM_ROW -> "clipboardBottomRow";
case ELEMENT_HANDWRITING_BOTTOM_ROW -> "handwritingBottomRow";
case ELEMENT_TEXT_EDIT -> "editing";
default -> null;
};
}
Expand Down
Loading
Loading