Fix invisible strokes from Ink API timestamp bug#1
Open
jdkruzr wants to merge 23 commits intojshph:mainfrom
Open
Fix invisible strokes from Ink API timestamp bug#1jdkruzr wants to merge 23 commits intojshph:mainfrom
jdkruzr wants to merge 23 commits intojshph:mainfrom
Conversation
Replace quick pages with an Inbox Capture template that renders a frontmatter zone (auto-filled created date, handwritable tags area), a divider line, and a lined content area below. This is the first step toward syncing handwritten notes to Obsidian as markdown files. - Add ML Kit Digital Ink Recognition dependency (19.0.0) - Add "inbox" native background type with drawInboxBg() renderer - Change quick page creation to use inbox background - Add InkTestView debug screen for testing recognition (~111ms on NoteAir5C) - Add CLAUDE.md with project setup and build instructions - Add docs/inbox-capture.md with full feature specification - Add IS_NEXT=false to gradle.properties for local builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ault When leaving an inbox capture page, strokes are classified by zone (tags vs content), recognized via ML Kit Digital Ink, and written as a markdown file with YAML frontmatter to the Obsidian inbox folder. The Notable page is deleted after successful sync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…plicit save Replace the handwritten frontmatter zones with a Compose UI toolbar at top: tag pills from vault (ranked by frequency×recency), text input with autocomplete filtering, and explicit Save & Exit / Back buttons. Pen toolbar moves to the bottom on inbox pages. - VaultTagScanner parses tags from inbox folder markdown frontmatter - Tags are cached on app start for instant loading - InboxSyncEngine now accepts tags from UI instead of stroke recognition - Frontmatter uses Obsidian format: created: "[[YYYY-MM-DD]]" - Settings page shows Inbox Capture section with configurable folder path - Double-sync guard prevents duplicate saves Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ne, clean library
- Fix non-writable area: setupSurface now excludes both top (inbox toolbar)
and bottom (pen toolbar) for capture pages, preventing pen input dead zones
- Make tag section collapsible: starts collapsed showing "Capture" toggle with
tag count, expands to show search + tag pills. Drawing surface updates dynamically
- Simplify library: remove folders/notebooks/import, show clean grid of captures
with prominent "New Capture" card
- Rename "Inbox Capture" to "Capture" throughout UI and settings
- Remove background template selector (all pages are captures now)
- Add sync overlay ("Saving to vault...") during capture save
- Default pen changed to fountain
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pre-context ML Kit assumes single-line input, so multi-line captures were poorly recognized. Now strokes are clustered into lines by vertical position, each line is recognized independently with its bounding box as the WritingArea, and the last 20 chars feed forward as pre-context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
RecognitionContext.builder() requires setPreContext() to be called. Always pass it (empty string for the first line). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the signing process with env vars in CLAUDE.md. Add *.jks to .gitignore to prevent committing keystores. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VaultTagScanner.cachedTags is now Compose mutableStateOf so the InboxToolbar automatically picks up tags when refreshCache() runs (either at startup or after changing the vault path in settings). Also add release build best practices to CLAUDE.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tency Three interconnected bugs prevented the fountain pen from working correctly as the default nib: 1. Race condition in pen initialization: setupSurface() calls openRawDrawing() which resets the Onyx SDK stroke style to its default. Because updatePenAndStroke() ran synchronously in surfaceCreated while updateActiveSurface() ran in a coroutine, the pen style was always overwritten before the first stroke. Fix: updatePenAndStroke() now runs inside updateActiveSurface() after setupSurface() completes. 2. Fountain pen bitmap replay rendered as ballpoint: The NeoFountainPenV2 SDK wrapper returned null PenPathResults during offline replay, producing uniform-width strokes that lost all pressure variation on any screen redraw (menu open, undo, dropdown). Fix: switched fountain pen replay to the custom drawFountainPenStroke renderer which explicitly varies stroke width per-point based on pressure. Deleted the now-unused NeoFountainPenV2Wrapper. 3. Light pressure produced invisible strokes: The linear pressure normalization (pressure/maxPressure) meant a gentle touch at ~200/4096 mapped to 0.05, barely visible. Fix: applied sqrt curve so the same touch maps to ~0.22, making light strokes clearly visible while preserving full range at heavy pressure. Refactoring: - Centralized pen defaults into Pen.DEFAULT and Pen.DEFAULT_SETTINGS - Added Pen.strokeStyle property, replacing standalone penToStroke() function - Extracted calculateExcludeHeights() from updateActiveSurface() - Removed redundant updatePenAndStroke() calls from observers that already call updateActiveSurface() - Pen.fromString() now falls back to Pen.DEFAULT instead of hardcoded BALLPEN Also adds a "Clear all pages" button in settings with confirmation dialog. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stroke points now store the actual delta time (dt) from the Onyx SDK's TouchPoint.timestamp instead of leaving it null. Previously, the ML Kit recognizer fell back to synthetic 10ms-apart timestamps, losing all real pen dynamics (writing speed, pauses between letters, stroke duration). This data is critical for ML Kit to disambiguate characters. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move pen toolbar toggle to InboxToolbar at the top of the screen so it's away from the writing hand. When hidden on inbox pages, the bottom toolbar is fully removed (no leftover button to ghost-tap). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Save & Exit now returns to the library immediately instead of blocking while sync runs. A SyncState singleton with its own coroutine scope handles background sync, and the library shows a "Syncing..." overlay on pages still processing. Pages are no longer deleted after sync — they stay in the library. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove ML Kit Digital Ink Recognition dependency and all related code. Handwriting recognition now uses the Boox firmware's built-in MyScript engine via AIDL IPC, which produces significantly better results. - Add AIDL interface for com.onyx.android.ksync HWR service - Add OnyxHWREngine with protobuf encoding and service binding - Simplify InboxSyncEngine to use only OnyxHWR (no fallback) - Remove InkTestView debug screen and its navigation wiring - Fix CountDownLatch reuse bug on service reconnection - Make Context non-nullable in sync path (always available) - Remove redundant DB query in sync flow Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap out manual Path-based pen rendering (ballpen, fountain, brush, marker, pencil) and Onyx Neo*PenWrapper calls with androidx.ink's CanvasStrokeRenderer. Removes ~200 lines of custom drawing code. Onyx SDK live input path is unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move all editor tools (pen, eraser, lasso, line, undo/redo, image, home, menu) from bottom toolbar to a vertically-centered left-edge sidebar - Pen picker flyout with size/color options appears to the right of sidebar - Eraser flyout with pen/select eraser and scribble-to-erase toggle - Add wiki link [[]] and tag # annotation buttons to sidebar - Annotation mode: tap [[ or #, then draw a box over text to create an annotation - Annotations render as semi-transparent colored overlays (blue for wikilink, green for tag) - New Annotation entity in Room DB (v35) with type, bounding box, and page FK - Annotation data flows through PageDataManager, PageView, and AppRepository - One-shot annotation: mode resets after each box is drawn - Remove PositionedToolbar and bottom toolbar from EditorView Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move sidebar outside canvas SurfaceView (Row layout) so finger taps work even when Onyx SDK raw drawing is active - Add dashed stroke preview in annotation color (blue/green) when annotation mode is active, with e-ink refresh after box creation - Increase annotation overlay visibility (alpha 130, border 4px) - Add annotation mode observer to update pen stroke style immediately - Eraser now removes annotation boxes in addition to strokes - HWR sync recognizes annotated text inline: strokes inside [[]] boxes become [[wiki links]], strokes inside # boxes become #tags - Add e-ink refresh helper to sidebar for button state updates - Skip scribble-to-erase when annotation mode is active Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nc accuracy - Replace solid rectangle overlays with typographic indicators: wiki links show [[ ]] brackets flanking content, tags show # prefix, both with light color wash, rounded corners, and subtle underline - Expand canvas clip and e-ink refresh regions to include bracket/hash glyphs that extend beyond the annotation bounding box - Fix HWR annotation wrapping by diffing full-page vs non-annotation stroke recognition instead of recognizing annotation strokes in isolation (which had worse accuracy due to less context, e.g. "pkm" recognized as "plan") - Add 10s timeout to OnyxHWR calls to prevent infinite hang on service disconnect Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace upstream Ethran README with one that reflects what this fork actually is: a handwriting capture surface for Obsidian on Boox tablets. Covers the capture workflow, HWR pipeline, vault sync, editor changes, and the UX principles visible across the commit history. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ck, simplify CI workflows - Annotation create/delete now tracked in undo/redo history - Expand redraw area to include bracket/hash glyph visual bounds, fixing partial clipping - InboxSyncEngine: fall back to per-annotation HWR when diff-based approach has count mismatch - Simplify CI workflows: update action versions, use GITHUB_TOKEN, trigger release on tag push Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…estamps
toInkStroke() was passing per-point dt deltas directly as elapsed_time
instead of accumulating them. This caused the Jetpack Ink API to reject
strokes with INVALID_ARGUMENT ("duplicate position and elapsed_time"),
making them invisible despite being saved to the database. Particularly
severe on the Palma 2 Pro where the slower SoC produces more duplicate
sample points.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
toInkStroke()was passing per-pointdtdeltas directly aselapsedTimeMillisinstead of accumulating them into cumulative timestamps. The Jetpack Ink API rejects strokes where consecutive points share both position and elapsed time (INVALID_ARGUMENT: Inputs must not have duplicate position and elapsed_time), causing strokes to silently fail to render despite being saved to the database.Test plan
🤖 Generated with Claude Code