Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
204 commits
Select commit Hold shift + click to select a range
39b5c84
chore: update README badges [skip ci]
github-actions[bot] Aug 6, 2026
240e5ac
chore: update README badges [skip ci]
github-actions[bot] Aug 7, 2026
d4b578d
chore: update README badges [skip ci]
github-actions[bot] Aug 8, 2026
9f067bc
release: v4.0.9 release with bug fixes, Compose localization, and upd…
LeanBitLab Aug 8, 2026
ed9f33e
feat(i18n): add full Malayalam (values-ml) localization
LeanBitLab Aug 8, 2026
52eafa7
feat(i18n): add full Spanish US (values-es-rUS) localization
LeanBitLab Aug 8, 2026
9cee120
feat(i18n): add full Arabic (values-ar) localization
LeanBitLab Aug 8, 2026
3950d81
feat(i18n): add full French (values-fr) localization
LeanBitLab Aug 8, 2026
701a19a
feat(i18n): add full Portuguese (values-pt) localization
LeanBitLab Aug 8, 2026
6bccb81
feat(i18n): add full Urdu (values-ur) localization
LeanBitLab Aug 8, 2026
47a389b
feat(i18n): add full Greek (values-el) localization
LeanBitLab Aug 8, 2026
7716bfc
feat(i18n): add full German (values-de) localization
LeanBitLab Aug 8, 2026
82699df
feat(i18n): add full Italian (values-it) localization
LeanBitLab Aug 8, 2026
01d7e44
docs: update v4.0.9 release notes & changelog with 100% localizations
LeanBitLab Aug 8, 2026
37e35c9
release: v4.0.9 release with bug fixes, Compose localization, and upd…
LeanBitLab Aug 8, 2026
d9333db
feat(i18n): add full Malayalam (values-ml) localization
LeanBitLab Aug 8, 2026
9fba639
feat(i18n): add full Spanish US (values-es-rUS) localization
LeanBitLab Aug 8, 2026
a9dda65
feat(i18n): add full Arabic (values-ar) localization
LeanBitLab Aug 8, 2026
f2ffad1
feat(i18n): add full French (values-fr) localization
LeanBitLab Aug 8, 2026
290b705
feat(i18n): add full Portuguese (values-pt) localization
LeanBitLab Aug 8, 2026
fce2fb1
feat(i18n): add full Urdu (values-ur) localization
LeanBitLab Aug 8, 2026
e55f9ea
feat(i18n): add full Greek (values-el) localization
LeanBitLab Aug 8, 2026
7ff8dda
feat(i18n): add full German (values-de) localization
LeanBitLab Aug 8, 2026
79077aa
feat(i18n): add full Italian (values-it) localization
LeanBitLab Aug 8, 2026
10d5c27
docs: update v4.0.9 release notes & changelog with 100% localizations
LeanBitLab Aug 8, 2026
b1078c0
chore: update README badges [skip ci]
github-actions[bot] Aug 9, 2026
53be047
feat(handwriting): add option for plugin-specific language selection
LeanBitLab Aug 9, 2026
9895f1f
feat(handwriting): add spacebar label sync, dynamic locale listing, a…
LeanBitLab Aug 9, 2026
9c92982
perf(handwriting): add tag-keyed caching for getEffectiveDisplayName
LeanBitLab Aug 9, 2026
9786fe9
perf(handwriting): use atomic DisplayNameCache holder for thread-safe…
LeanBitLab Aug 9, 2026
6de9a1a
docs: add handwriting language selection to v4.0.9 release notes
LeanBitLab Aug 9, 2026
7ad812e
Merge branch 'beta1' into main
LeanBitLab Aug 9, 2026
3b40bb6
Merge branch 'main' of github.com:LeanBitLab/LeanType into main
LeanBitLab Aug 9, 2026
3c049e5
fix(suggestions): disarm delete mode on pick/click/clear and overrule…
LeanBitLab Aug 9, 2026
1e10e1c
docs: update release notes for #382 fix and personal dict blocklist o…
LeanBitLab Aug 9, 2026
772e2d3
feat(foldable): gate automatic screen profile detection behind pref_f…
LeanBitLab Aug 9, 2026
621217c
fix(keyboard): reset lastCustomIndex when toggling back from symbols …
LeanBitLab Aug 9, 2026
25161db
fix(autocorrect): enable dictionary engine when PREF_MORE_AUTO_CORREC…
LeanBitLab Aug 9, 2026
cd570f5
fix(imeOptions): add fallback for IME_FLAG_NAVIGATE_NEXT and PREVIOUS…
LeanBitLab Aug 9, 2026
dfc3c29
fix(handwriting): add SDK version guard and exception handling for ML…
LeanBitLab Aug 9, 2026
de2a67c
docs(releasenote): update v4.0.9 release notes with all sprint fixes
LeanBitLab Aug 9, 2026
f0636fd
docs(fastlane): update 4009.txt changelog for F-Droid release
LeanBitLab Aug 9, 2026
d2e0b42
chore: update README badges [skip ci]
github-actions[bot] Aug 10, 2026
0cf92cf
fix(input): prevent single-click backspace from bulk deleting numeric…
LeanBitLab Aug 10, 2026
eb9e990
release: v4.1.0 - single-click backspace fix for numeric sequences
LeanBitLab Aug 10, 2026
18a3133
fix(input): resolve physical keyboard toggle, standalone suggestion b…
LeanBitLab Aug 10, 2026
0ecbf95
fix(emoji): exempt Emoji and Clipboard keyboards from physical keyboa…
LeanBitLab Aug 10, 2026
5e6cbcc
fix(settings): restore foldable mode toggle in appearance settings an…
LeanBitLab Aug 10, 2026
651d529
feat(settings): add inline search option for list dialogs and handwri…
LeanBitLab Aug 10, 2026
20f3ac2
fix(inputlogic): handle CLEAR_HANDWRITING and handwriting UI keycodes…
LeanBitLab Aug 10, 2026
1698e5a
fix(handwriting): make handwriting canvas background transparent to p…
LeanBitLab Aug 10, 2026
b3935be
feat(clipboard): add right-swipe edit gesture and edit dialog for cli…
LeanBitLab Aug 10, 2026
8fe8781
refactor: replace AlertDialog clipboard edit with inline edit mode
LeanBitLab Aug 10, 2026
54e6d9d
fix: walk up view hierarchy to find ClipboardHistoryView ancestor
LeanBitLab Aug 10, 2026
8b44351
refactor: integrate clipboard edit UI directly into toolbar strip
LeanBitLab Aug 10, 2026
29a6379
fix(clipboard): route space/delete swipes to edit buffer & fix tap cu…
LeanBitLab Aug 10, 2026
2e83e27
fix(suggestions): remove hardcoded android:maxWidth=100dp from sugges…
LeanBitLab Aug 10, 2026
d66cda3
fix(toolbar): allow clipboard toolbar keys to auto-span when mAutoSpa…
LeanBitLab Aug 10, 2026
5d79e25
fix(layout): fix suggestions_strip 0dp width and clipboard_strip layo…
LeanBitLab Aug 10, 2026
0a40aa6
fix(clipboard): refine clipboard toolbar auto-spanning logic
LeanBitLab Aug 10, 2026
99c66dd
fix(clipboard): disable auto-spanning when total keys width exceeds c…
LeanBitLab Aug 10, 2026
bcf8e11
fix(clipboard): format clipboard toolbar keys identically to normal t…
LeanBitLab Aug 10, 2026
e4938b6
fix(clipboard): restore auto-spanning for clipboard toolbar keys when…
LeanBitLab Aug 10, 2026
b64018a
docs(release): update v4.1.0 release notes with complete changelog
LeanBitLab Aug 10, 2026
7a888e2
docs(fastlane): update 4100.txt changelog with complete v4.1.0 releas…
LeanBitLab Aug 10, 2026
e3050c9
docs(release): format v4.1.0 release notes to be compact and high-den…
LeanBitLab Aug 10, 2026
4f189f7
docs(release): remove suggestion strip truncation entry from v4.1.0 c…
LeanBitLab Aug 10, 2026
bf097ac
fix(clipboard): replace text Save button with checkmark icon ImageBut…
LeanBitLab Aug 10, 2026
4e9ce87
docs(release): update inline clipboard edit button representation in …
LeanBitLab Aug 10, 2026
35b4f85
chore: update README badges [skip ci]
github-actions[bot] Aug 11, 2026
bba86be
feat(otp): replace RECEIVE_SMS with privacy-first NotificationListene…
LeanBitLab Aug 11, 2026
d97b505
style(settings): set default landscape keyboard height scale to 45%
LeanBitLab Aug 11, 2026
41391fc
fix(clipboard): intercept layout switch keys locally in edit mode to …
LeanBitLab Aug 11, 2026
6fdf8e9
fix(gesture): suppress word-gesture typing while clipboard inline edi…
LeanBitLab Aug 11, 2026
0ae0f2a
fix(clipboard): unify inline search/edit swipe routing, text scrollin…
LeanBitLab Aug 11, 2026
69fbe01
docs(release): add v4.1.1 release notes and fastlane changelog 4101.txt
LeanBitLab Aug 11, 2026
93bd7d3
chore: update README badges [skip ci]
github-actions[bot] Aug 12, 2026
1894f75
chore: update README badges [skip ci]
github-actions[bot] Aug 13, 2026
b5b4c04
chore: update README badges [skip ci]
github-actions[bot] Aug 14, 2026
0beab06
chore: update README badges [skip ci]
github-actions[bot] Aug 15, 2026
ed35041
chore: update README badges [skip ci]
github-actions[bot] Aug 16, 2026
70bb579
chore: update README badges [skip ci]
github-actions[bot] Aug 17, 2026
2856009
chore: update README badges [skip ci]
github-actions[bot] Aug 18, 2026
6c32629
chore: update README badges [skip ci]
github-actions[bot] Aug 19, 2026
afde87a
feat(voice): add AIDL contract, parcelables, and build configuration …
LeanBitLab Aug 12, 2026
848d3a7
feat(voice): implement VoicePluginManager and VoiceInputManager host …
LeanBitLab Aug 12, 2026
370d9a1
feat(voice): implement VoiceSettingsScreen, debug stub service, and n…
LeanBitLab Aug 12, 2026
e8aacdf
fix(voice): resolve compilation imports, SwitchPreference parameters,…
LeanBitLab Aug 12, 2026
81340b9
feat(voice): extract AIDL contract into shared root module voice-cont…
LeanBitLab Aug 12, 2026
727ccbf
feat(voice): implement Phase 2 companion offline voice plugin with Vo…
LeanBitLab Aug 12, 2026
8850f19
feat(voice): integrate production IME key event routing, lazy IPC bin…
LeanBitLab Aug 12, 2026
ee7ec0f
fix(voice): declare BIND_VOICE_PLUGIN uses-permission in app AndroidM…
LeanBitLab Aug 12, 2026
014da0a
feat(voice): add Delete Model actions for Vosk and Whisper in VoiceSe…
LeanBitLab Aug 12, 2026
f3495d8
feat(voice): add async coroutine model import, automatic UI status po…
LeanBitLab Aug 12, 2026
4a96c92
fix(voice): declare package visibility queries in host and plugin man…
LeanBitLab Aug 12, 2026
4273929
refactor(voice): optimize UI status polling with isActive lifecycle c…
LeanBitLab Aug 12, 2026
b0485c7
fix(voice): set isBound = true in ServiceConnection.onServiceConnecte…
LeanBitLab Aug 12, 2026
e7eaefa
fix(voice): parse full sentence result when acceptWaveForm returns tr…
LeanBitLab Aug 12, 2026
2bfcb8a
fix(voice): use RelativeLayout.LayoutParams for VoiceOverlayView atta…
LeanBitLab Aug 12, 2026
b011939
fix(voice): implement self-recovering session teardown in VoiceEngine…
LeanBitLab Aug 12, 2026
ceb4d82
fix(voice): replace VoiceOverlayView with Toast state notifications a…
LeanBitLab Aug 12, 2026
ca20b0a
test(voice): add byte-level pipe tracing for audio capture and ASR en…
LeanBitLab Aug 12, 2026
eae9f94
fix(voice): duplicate PFD in VoskEngine and defer readSide closure to…
LeanBitLab Aug 12, 2026
3372cd2
test(voice): add first audio sample PCM logging and callback delivery…
LeanBitLab Aug 12, 2026
cf653fb
feat(voice): add proofreading-style toolbar pulse animation on voice …
LeanBitLab Aug 12, 2026
f4a663a
feat(voice): trigger SuggestionStripView showLoadingAnimation and hid…
LeanBitLab Aug 12, 2026
6efc262
chore(voice): finalize offline voice input integration, settings scre…
LeanBitLab Aug 12, 2026
bfacb79
Refactor(voice): Separate voice plugin to standalone repository and m…
LeanBitLab Aug 14, 2026
68c3e09
feat(floating): restore SYSTEM_ALERT_WINDOW permission for floating m…
LeanBitLab Aug 14, 2026
38258da
feat(voice): enable voice input key when offline voice input plugin i…
LeanBitLab Aug 14, 2026
3871e04
feat(settings): add Whisper keep-loaded preference, hybrid mode notic…
LeanBitLab Aug 14, 2026
a232388
fix(voice): increase handshake timeout to 8s, pre-bind voice plugin, …
LeanBitLab Aug 14, 2026
aef0bc6
fix(voice): start AudioRecord immediately on session handshake with M…
LeanBitLab Aug 14, 2026
5dbba44
fix(voice): close and null PFDs properly, join audioThread on stop, a…
LeanBitLab Aug 14, 2026
e9b9210
fix(trace): add detailed trace logging for onFinal and handleFinalText
LeanBitLab Aug 14, 2026
779fb5a
fix(voice): forward currentSubtypeLocale language tag to VoiceSession…
LeanBitLab Aug 14, 2026
d11b1e9
feat(settings): enable Phase 2.3 Hybrid mode in Voice Settings
LeanBitLab Aug 14, 2026
f0309cb
fix(voice): deduplicate state transitions, eliminate redundant toasts…
LeanBitLab Aug 15, 2026
9e2f054
fix(voice): optimize partial text dispatch and add detailed state tra…
LeanBitLab Aug 15, 2026
c369d9a
feat(hybrid): support continuous multi-segment dictation without prem…
LeanBitLab Aug 15, 2026
653aac5
fix(audio): guard audio write loop exception logging during shutdown
LeanBitLab Aug 15, 2026
bb3884e
feat(voice): implement voice commands, smart spoken punctuation, and …
LeanBitLab Aug 15, 2026
672ffca
feat(voice): implement multi-clause linear tokenization for voice com…
LeanBitLab Aug 15, 2026
f4666c4
fix(voice): implement Universal Batch-Edit Fallback Pattern and curso…
LeanBitLab Aug 15, 2026
138291d
fix(voice): universalize deterministic batch-edit partial replacement
LeanBitLab Aug 15, 2026
83ba816
fix(voice): add requestShowSelf, safe-delete guard, and hard reset in…
LeanBitLab Aug 15, 2026
93f03ba
fix(voice): direct pure ASR commits with clean sentence capitalization
LeanBitLab Aug 15, 2026
af25073
clean(settings): remove debug options and test scaffolding from Voice…
LeanBitLab Aug 15, 2026
828c76b
feat(voice): in-app model manager dialog with DownloadManager and fla…
LeanBitLab Aug 15, 2026
cd401e7
fix(voice): oneway AIDL import, suspend-based binding, and safe goAsy…
LeanBitLab Aug 15, 2026
b18988d
fix(voice): continuous polling and active installed model state track…
LeanBitLab Aug 15, 2026
07761d8
fix(voice): save installed model tracking to default SharedPreferences
LeanBitLab Aug 15, 2026
f90eaad
refactor(voice): redesign speech models dialog to match native dictio…
LeanBitLab Aug 15, 2026
18a0b91
refactor(voice): remove recommended text and fallbacks from speech mo…
LeanBitLab Aug 15, 2026
c69b79e
feat(voice): dynamic keyboard language matching and expandable multil…
LeanBitLab Aug 15, 2026
daf029c
fix(voice): tag Indian English as en-in to group under other languages
LeanBitLab Aug 15, 2026
924b767
fix(layout): restrict number row injection to primary symbols view (#…
LeanBitLab Aug 16, 2026
61b3661
fix(toolbar): restore Gravity.END fallback and fix split mode auto-sp…
LeanBitLab Aug 16, 2026
e5c7c6d
fix(cursor): unify horizontal space swipe to use relative DPAD arrow …
LeanBitLab Aug 16, 2026
00918d8
fix(input): finalize composition on editor action when not auto-corre…
LeanBitLab Aug 16, 2026
8cbb690
fix(theme): isolate key borders setting strictly to keyboard keys
LeanBitLab Aug 16, 2026
ec11286
fix(clipboard): maintain rounded bordered cards when key borders are …
LeanBitLab Aug 16, 2026
615c840
fix(theme): preserve spacebar button shape and background when key bo…
LeanBitLab Aug 16, 2026
aa274b5
feat(clipboard): add option to select clipboard keys alignment
LeanBitLab Aug 16, 2026
3826b6d
fix(voice): unblock launcher search, add silence timeout setting, and…
LeanBitLab Aug 16, 2026
93c6911
fix(voice): implement delta streaming and preserve words on empty fin…
LeanBitLab Aug 16, 2026
e44df34
feat(voice): restore 3 seconds silence timeout option in settings
LeanBitLab Aug 16, 2026
fd43558
perf(voice): implement zero-allocation audio DSP pipeline with contin…
LeanBitLab Aug 16, 2026
9adf229
fix(voice): handle disjoint utterance segmentation and restore raw PC…
LeanBitLab Aug 16, 2026
5a2fdac
fix(voice): call finishComposingText before committing trailing space…
LeanBitLab Aug 16, 2026
ff5c03e
feat(voice): migrate to Distil-Whisper and remove legacy Vosk
LeanBitLab Aug 16, 2026
3e977de
feat(voice): optimize whisper model catalog with compact Q5_1 quantiz…
LeanBitLab Aug 16, 2026
634efb7
refactor(voice): completely remove hybrid mode and enforce direct Whi…
LeanBitLab Aug 16, 2026
1a89020
feat(voice): overhaul voice UI to in-toolbar status bar and fix silen…
LeanBitLab Aug 16, 2026
067655d
feat(voice): improve voice indicator UI with visualizer and fix close…
LeanBitLab Aug 17, 2026
6c23906
fix(voice): fix button theme colors on voice toolbar and eliminate se…
LeanBitLab Aug 17, 2026
7215bab
refactor(voice): redesign speech models UI, status badge, and model d…
LeanBitLab Aug 17, 2026
33a4566
fix(voice): polish Whisper Models dialog layout, Remove buttons, and …
LeanBitLab Aug 17, 2026
7b6bb17
feat(voice): add always keep loaded option, outlined import button, a…
LeanBitLab Aug 17, 2026
0d09559
feat(settings): add Updates screen with GitHub release checks, change…
LeanBitLab Aug 17, 2026
b326d34
feat(updates): add in-app streaming self-updater for standardfull, si…
LeanBitLab Aug 17, 2026
02bbe7c
fix(manifest): remove signature permission BIND_VOICE_PLUGIN to decou…
LeanBitLab Aug 17, 2026
24dfd62
style(ui): fold changelog by default, rename model dialog button to D…
LeanBitLab Aug 17, 2026
5a426cc
fix(voice): guarantee Remove button visibility when Whisper model is …
LeanBitLab Aug 17, 2026
f5fc201
feat(voice): add Uninstall Plugin button and flavor-specific Download…
LeanBitLab Aug 17, 2026
6b2859a
fix(voice): redirect Uninstall button to Voice Plugin App Info detail…
LeanBitLab Aug 17, 2026
1a52927
feat(updates): add official community & social links with platform icons
LeanBitLab Aug 19, 2026
d0d2556
style(updates): move What's New section below Support Development sec…
LeanBitLab Aug 19, 2026
af9739b
fix(updates): reactively toggle check frequency visibility and remove…
LeanBitLab Aug 19, 2026
89ce41f
feat(toolbar): unify toolbar and clipboard keys alignment option
LeanBitLab Aug 19, 2026
175af83
fix(toolbar): calibrate key auto-spanning threshold and preserve key …
LeanBitLab Aug 19, 2026
4ce0496
fix(toolbar): enforce minimum key spanning width and mode-based conta…
LeanBitLab Aug 19, 2026
1e07492
feat(dictionary): add personal dictionary learning threshold slider a…
LeanBitLab Aug 19, 2026
11bce1e
fix(dictionary): remove restrictive autocorrect filter and execute us…
LeanBitLab Aug 19, 2026
742d9c4
fix(prediction): add ngram backoff to ensure continuous next-word sug…
LeanBitLab Aug 19, 2026
08efec0
fix(suggest): enforce defensive copying in next-word suggestions cach…
LeanBitLab Aug 19, 2026
acda5b6
docs: overhaul README with 4-flavor comparison matrix, updated featur…
LeanBitLab Aug 19, 2026
d1db6c9
docs(readme): update accurate APK sizes across all four flavors
LeanBitLab Aug 19, 2026
8daa6cf
docs(readme): add LeanType Translation Plugin to ecosystem, features,…
LeanBitLab Aug 19, 2026
ac81781
docs(readme): add Translation capabilities row to Flavor Comparison t…
LeanBitLab Aug 19, 2026
0227ac1
docs(readme): clarify dual-engine translation options (AI provider vs…
LeanBitLab Aug 19, 2026
5f14146
docs(readme): add Open Collective donation link and badges
LeanBitLab Aug 19, 2026
e46372c
chore: add open_collective to FUNDING.yml
LeanBitLab Aug 19, 2026
8cfe624
docs(readme): clean up Whisper model references across documentation
LeanBitLab Aug 19, 2026
cd11b7a
docs(readme): specify multilingual Whisper models (Tiny, Base, Small)…
LeanBitLab Aug 19, 2026
1679d09
feat(ui): harmonize Open Collective & GitHub Sponsor UI with official…
LeanBitLab Aug 19, 2026
62c780f
docs: overhaul FEATURES.md with complete index, updated feature catal…
LeanBitLab Aug 19, 2026
d141a10
docs: add clipboard inline swipe-to-edit, sliding selection, and priv…
LeanBitLab Aug 19, 2026
a50dc4b
docs: remove emoji sliding explanation to keep documentation focused
LeanBitLab Aug 19, 2026
44ef84a
feat(voice): add dedicated voice recognition language selector with a…
LeanBitLab Aug 19, 2026
4dbd6bb
feat(debug): add Toast feedback when tapping dump dictionary options
LeanBitLab Aug 19, 2026
3a4eef6
chore(release): bump version to 4.1.2 (versionCode 4102)
LeanBitLab Aug 19, 2026
85dd29b
docs(release): update comprehensive release notes for v4.1.2
LeanBitLab Aug 19, 2026
966cb9e
docs(release): make v4.1.2 release notes compact and focused
LeanBitLab Aug 19, 2026
01a58c1
docs(release): trim unnecessary mentions from v4.1.2 release notes
LeanBitLab Aug 19, 2026
f51df8c
docs(fastlane): add changelog for release 4102 (v4.1.2)
LeanBitLab Aug 19, 2026
0c3ac29
feat(updates): synchronize in-app What's New changelog with v4.1.2 re…
LeanBitLab Aug 19, 2026
dfab03c
fix(ui): restore official two-tone vector paths for Open Collective i…
LeanBitLab Aug 19, 2026
6d9fe2b
fix(ui): update Open Collective vector with precise Simple Icons path
LeanBitLab Aug 19, 2026
f0ff166
docs(readme): enhance badge contrast, clean overview formatting, ment…
LeanBitLab Aug 19, 2026
3fad730
Merge upstream LeanBitLab/LeanType v4.1.2
AsafMah Aug 20, 2026
b6f2eb8
fix(merge): repair two fork regressions from the v4.1.2 merge
AsafMah Aug 20, 2026
dcfe997
docs(changelog): correct PR references to #137
AsafMah Aug 20, 2026
e46454e
test: drop the two upstream-defect guards, fixed in v4.1.2
AsafMah Aug 20, 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
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

github: LeanBitLab
patreon: # [username]
open_collective: # [username]
open_collective: leanbitlab-org
ko_fi: # [username]
tidelift: # [platform-name/package-name]
community_bridge: # [cloud-transport-project-name]
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ and this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html)

## [Unreleased]

### Upstream
- Merged **LeanBitLab/LeanType v4.1.2** (pinned at `8720abeb`, covering v4.0.9–v4.1.2, 200 commits) — adds a clipboard edit mode, a personal-dictionary learning threshold, physical-keyboard and suggestion fixes, and Compose localization. LeanTypeDual retains its distinct `applicationId`, fork version, privacy tiers, Java fallback gesture engine, two-thumb typing, and persistent custom layout slots. (#137)

### Fixed
- **Whole-word backspace keeps working after the upstream merge.** Upstream's fix for single-click backspace bulk-deleting numeric sequences was auto-merged in a way that stopped the two-thumb whole-word delete from clearing the composing span, leaving partial words behind. Both behaviours now coexist. (#137)
- **Custom layouts still restore after leaving symbol mode.** Upstream resets the remembered custom layout when switching back to the alphabet, which conflicted with this fork's persistent custom layout slots. (#137)

### Reliability & testing
- **Dropped both `runTests` skip guards for defects inherited from upstream** — subtype edit persistence and symbol-prefixed regex expansion are both fixed in upstream v4.1.2. Verified twice: on a pristine upstream checkout at the tag, and in the merged tree. Those two tests now actually execute on CI instead of returning early. (#137)
- **Fixed a latent test-harness bug** where `setText` accepted a `requireIdle` parameter it never passed through, so `reset()` could not tolerate leftover delayed messages. Harmless until the merge shifted JUnit's hash-based test ordering, at which point it failed an unrelated backspace test. (#137)

## [0.2.0] - 2026-08-06

### Upstream
Expand Down
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ plugins {
kotlin("android")
kotlin("plugin.serialization") version "2.2.21"
kotlin("plugin.compose") version "2.2.21"
kotlin("plugin.parcelize")
}

// Load keystore properties
Expand Down Expand Up @@ -155,6 +156,7 @@ android {
viewBinding = true
buildConfig = true
compose = true
aidl = true
}

externalNativeBuild {
Expand Down Expand Up @@ -225,7 +227,6 @@ android {
}

dependencies {

// androidx
implementation("androidx.core:core-ktx:1.16.0") // 1.17 requires SDK 36
implementation("androidx.recyclerview:recyclerview:1.4.0")
Expand Down
5 changes: 4 additions & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@
-dontwarn java.lang.management.**
-dontwarn org.joda.time.**

# Keep handwriting plugin interface and listener to prevent parameter removal/signature optimization
# Keep offline voice plugin AIDL interface and parcelable classes
-keep class com.leanbitlab.leantype.voice.** { *; }
-keep interface com.leanbitlab.leantype.voice.** { *; }

-keep interface helium314.keyboard.latin.handwriting.HandwritingRecognizer {
<methods>;
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service
android:name="helium314.keyboard.latin.voice.DebugVoiceEngineService"
android:exported="false" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin.voice

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.ParcelFileDescriptor
import com.leanbitlab.leantype.voice.IVoiceCallback
import com.leanbitlab.leantype.voice.IVoiceEngine
import com.leanbitlab.leantype.voice.ModelImportRequest
import com.leanbitlab.leantype.voice.ModelState
import com.leanbitlab.leantype.voice.VoiceConstants
import com.leanbitlab.leantype.voice.VoiceEngineInfo
import com.leanbitlab.leantype.voice.VoiceSessionConfig
import helium314.keyboard.latin.utils.Log
import java.io.FileInputStream
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean

class DebugVoiceEngineService : Service() {

private val executor = Executors.newSingleThreadExecutor()
private val isSessionActive = AtomicBoolean(false)

private val binder = object : IVoiceEngine.Stub() {
override fun getInfo(): VoiceEngineInfo {
return VoiceEngineInfo(
contractVersion = VoiceConstants.VOICE_CONTRACT_VERSION,
pluginId = "helium314.keyboard.latin.voice.debug",
displayName = "Debug Voice Stub Engine",
supportsVosk = true,
supportsWhisper = true,
supportsHybrid = true
)
}

override fun getModelState(engineType: String?): ModelState {
return ModelState(
engineType = engineType ?: VoiceConstants.ENGINE_VOSK,
state = ModelState.STATE_READY,
message = "Debug stub model ready"
)
}

override fun importModel(request: ModelImportRequest?) {
Log.i(TAG, "Debug stub received model import request for ${request?.engineType}")
try {
request?.file?.close()
} catch (_: Exception) {}
}

override fun unloadModel(engineType: String?) {
Log.i(TAG, "Debug stub unload model: $engineType")
}

override fun deleteModel(engineType: String?) {
Log.i(TAG, "Debug stub delete model: $engineType")
}

override fun startSession(
config: VoiceSessionConfig?,
audioInput: ParcelFileDescriptor?,
callback: IVoiceCallback?
) {
Log.i(TAG, "Debug stub starting session: ${config?.sessionId}, mode: ${config?.mode}")
isSessionActive.set(true)

executor.execute {
try {
callback?.onSessionStarted()

// Read incoming audio pipe data in background thread
if (audioInput != null) {
val input = FileInputStream(audioInput.fileDescriptor)
val buffer = ByteArray(960)
var bytesRead = 0
var totalRead = 0

while (isSessionActive.get() && input.read(buffer).also { bytesRead = it } != -1) {
totalRead += bytesRead
if (totalRead > 30000 && isSessionActive.get()) {
callback?.onPartial("test partial")
}
}
}

if (isSessionActive.get()) {
Thread.sleep(300)
callback?.onFinal("test final")
}
} catch (e: Exception) {
Log.e(TAG, "Debug stub session error", e)
callback?.onError(VoiceConstants.VOICE_ERROR_UNKNOWN, e.message)
} finally {
try {
audioInput?.close()
} catch (_: Exception) {}
callback?.onSessionEnded()
isSessionActive.set(false)
}
}
}

override fun stopSession() {
Log.i(TAG, "Debug stub stopSession called")
isSessionActive.set(false)
}

override fun cancelSession() {
Log.i(TAG, "Debug stub cancelSession called")
isSessionActive.set(false)
}

override fun release() {
Log.i(TAG, "Debug stub release called")
isSessionActive.set(false)
}
}

override fun onBind(intent: Intent?): IBinder {
Log.i(TAG, "DebugVoiceEngineService bound")
return binder
}

override fun onDestroy() {
super.onDestroy()
executor.shutdownNow()
}

companion object {
private const val TAG = "DebugVoiceEngineService"
}
}
34 changes: 31 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,22 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
<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" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />

<queries>
<package android:name="com.leanbitlab.leantype.voice.offline" />
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="sms" />
</intent>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="smsto" />
</intent>
</queries>

<application android:label="@string/english_ime_name"
android:name="helium314.keyboard.latin.App"
Expand Down Expand Up @@ -48,6 +59,15 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
<meta-data android:name="android.view.im" android:resource="@xml/method_dummy" />
</service>

<service android:name=".OtpNotificationListenerService"
android:label="@string/auto_read_otp"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>

<service android:name=".spellcheck.AndroidSpellCheckerService"
android:label="@string/spell_checker_service_name"
android:permission="android.permission.BIND_TEXT_SERVICE"
Expand Down Expand Up @@ -128,6 +148,14 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
android:resource="@xml/provider_paths" />
</provider>

<receiver
android:name="helium314.keyboard.latin.voice.DownloadCompleteReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>

<!-- Disable WorkManager auto-initializer; App implements Configuration.Provider instead.
Required for ML Kit Digital Ink plugin loaded via DexClassLoader. -->
<provider
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.leanbitlab.leantype.voice;

oneway interface IVoiceCallback {
void onSessionStarted();
void onPartial(String text);
void onFinal(String text);
void onError(int code, String message);
void onSessionEnded();
}
24 changes: 24 additions & 0 deletions app/src/main/aidl/com/leanbitlab/leantype/voice/IVoiceEngine.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.leanbitlab.leantype.voice;

import com.leanbitlab.leantype.voice.IVoiceCallback;
import com.leanbitlab.leantype.voice.VoiceEngineInfo;
import com.leanbitlab.leantype.voice.ModelState;
import com.leanbitlab.leantype.voice.ModelImportRequest;
import com.leanbitlab.leantype.voice.VoiceSessionConfig;
import android.os.ParcelFileDescriptor;

interface IVoiceEngine {
VoiceEngineInfo getInfo();
ModelState getModelState(String engineType);
oneway void importModel(in ModelImportRequest request);
void unloadModel(String engineType);
void deleteModel(String engineType);
void startSession(
in VoiceSessionConfig config,
in ParcelFileDescriptor audioInput,
IVoiceCallback callback
);
void stopSession();
void cancelSession();
void release();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.leanbitlab.leantype.voice;

parcelable ModelImportRequest;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.leanbitlab.leantype.voice;

parcelable ModelState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.leanbitlab.leantype.voice;

parcelable VoiceEngineInfo;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.leanbitlab.leantype.voice;

parcelable VoiceSessionConfig;
Loading
Loading