- PROGRESS.md: remove stale known issues (all fixed), add post-Phase 10 feature polish section covering toolbar redesign, 4 pen sizes, line/box/move tools, edge swipe nav, page reorder, notebook rename, filter/sort, JPG export, clipboard ops, startup state restoration, and DB migrations - PROJECT_PLAN.md: add Phase 11 (Server Sync Integration) and Phase 12 (Notebook Backup/Export) with step breakdowns - DESIGN.md: add Tools table, sync architecture section, backup/export design, JPG export, stroke styles, startup state restoration, edge swipe nav; update rendering strategy (3-layer compositing), source tree, schema, and pen sizes - CLAUDE.md: update build commands, architecture, source tree, and key conventions to match current codebase Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
240 lines
12 KiB
Markdown
240 lines
12 KiB
Markdown
# PROGRESS.md — eng-pad Implementation Progress
|
|
|
|
This file tracks completed work and decisions. Updated after every step.
|
|
See PROJECT_PLAN.md for the full step list.
|
|
|
|
## Completed
|
|
|
|
### Phase 0: Project Documents (2026-03-24)
|
|
|
|
- [x] 0.1: Created DESIGN.md — full technical design covering architecture,
|
|
data model, coordinate system, rendering, input handling, and source tree.
|
|
- [x] 0.2: Created PROJECT_PLAN.md — discrete steps grouped by phase with
|
|
checkboxes and file references.
|
|
- [x] 0.3: Created PROGRESS.md — this file.
|
|
- [x] 0.4: Updated CLAUDE.md — build commands, source tree, project doc
|
|
pointers.
|
|
|
|
### Phase 1: Project Skeleton + Data Layer (2026-03-24)
|
|
|
|
- [x] 1.1: Generated Android project — Gradle 8.14.2, AGP 8.10.1, Kotlin 2.1.20
|
|
- [x] 1.2: Version catalog with Compose BOM 2026.03.00, Room 2.8.4,
|
|
Navigation 2.9.7, Lifecycle 2.10.0
|
|
- [x] 1.3: Lint configured — warningsAsErrors, AGP version check suppressed
|
|
(AGP 9.x needs Gradle 9.x)
|
|
- [x] 1.4: Room entities: Notebook, Page, Stroke, PageSize enum
|
|
- [x] 1.5: Converters: FloatArray <-> ByteArray (packed little-endian)
|
|
- [x] 1.6: DAOs: NotebookDao, PageDao, StrokeDao
|
|
- [x] 1.7: EngPadDatabase (Room, version 1)
|
|
- [x] 1.8: NotebookRepository, PageRepository
|
|
- [x] 1.9: Unit tests: StrokeBlobTest (6 tests), PageSizeTest (4 tests) — all pass
|
|
- Foojay resolver added for automatic JDK toolchain download
|
|
- compileSdk/targetSdk bumped to 36 (required by latest androidx dependencies)
|
|
|
|
### Phase 2: Notebook List Screen (2026-03-24)
|
|
|
|
- [x] 2.1: MainActivity with Compose NavHost (three routes: notebooks, pages, editor)
|
|
- [x] 2.2: NotebookListViewModel with StateFlow, create/delete operations
|
|
- [x] 2.3: NotebookListScreen — lazy list, create dialog (title + page size radio),
|
|
long-press delete with confirmation, empty state
|
|
- [x] 2.4: Auto-create page 1 in NotebookRepository.create()
|
|
- [x] 2.5: Navigation wired — tap notebook -> pages stub, editor stub
|
|
- EngPadTheme: high-contrast light color scheme (black on white for e-ink)
|
|
|
|
### Phase 3: Canvas — Basic Drawing (2026-03-24)
|
|
|
|
- [x] 3.1-3.4: PadCanvasView — stylus input with historical points, Path/Paint
|
|
stroke rendering, direct path drawing (no backing bitmap), 60pt grid
|
|
drawn in screen space with pixel-snapped positions, Matrix coordinate
|
|
transform (canonical <-> screen)
|
|
- [x] 3.5: CanvasState — tool enum (PEN, LINE, BOX, ERASER, SELECT, MOVE),
|
|
zoom/pan state, PenSize enum with 4 sizes
|
|
- [x] 3.6: EditorViewModel — loads strokes from Room, saves on completion
|
|
- [x] 3.7: EditorScreen + Toolbar — Compose wrapper with AndroidView,
|
|
icon-button toolbar with long-press menus for pen size and line style
|
|
- [x] 3.8: NavGraph updated — pages route auto-navigates to first page's editor,
|
|
page size passed through route params
|
|
- Used KTX Canvas extensions (withMatrix, withScale, createBitmap) per lint
|
|
- ClickableViewAccessibility suppressed on PadCanvasView (drawing view)
|
|
|
|
### Phase 4: Zoom and Pan (2026-03-24)
|
|
|
|
- [x] 4.1: ScaleGestureDetector with focal-point zoom (dynamic min-4x)
|
|
- [x] 4.2: Finger drag for pan with multi-pointer tracking, pan clamped
|
|
so page always fills viewport
|
|
- [x] 4.3: Input routing by tool type already in place from Phase 3
|
|
- Zoom/pan state managed locally in PadCanvasView for responsiveness,
|
|
synced to ViewModel on gesture end
|
|
- Minimum zoom computed dynamically from page/view dimensions
|
|
|
|
### Phase 5: Eraser (2026-03-24)
|
|
|
|
- [x] 5.1-5.3: Stroke-level eraser with bounding box hit test (42pt radius),
|
|
processes historical touch points for thorough erasing, deletes from
|
|
view + Room DB
|
|
|
|
### Phase 6: Undo/Redo (2026-03-24)
|
|
|
|
- [x] 6.1: UndoableAction interface, AddStrokeAction, DeleteStrokeAction
|
|
- [x] 6.2: UndoManager with undo/redo stacks (depth 50), StateFlow for canUndo/canRedo
|
|
- [x] 6.3: EditorViewModel rewired — stroke add/delete go through UndoManager,
|
|
visual callbacks sync canvas view without full reload
|
|
- [x] 6.4: 9 unit tests for UndoManager (perform, undo, redo, depth limit, clear, no-ops)
|
|
- Toolbar now has undo/redo buttons with enabled state
|
|
|
|
### Phase 7: Selection — Move, Copy, Delete (2026-03-24)
|
|
|
|
- [x] 7.1-7.2: Rectangle selection with dashed rect and blue highlight
|
|
- [x] 7.3: Delete, drag-to-move, copy operations with toolbar buttons
|
|
- [x] 7.4: Full undo integration — DeleteMultipleStrokesAction, MoveStrokesAction,
|
|
CopyStrokesAction
|
|
- Drag existing selection to move, tap outside to deselect
|
|
|
|
### Phase 8: Multi-Page Navigation (2026-03-24)
|
|
|
|
- [x] 8.1: PageListScreen — adaptive grid of page cards with correct aspect ratio
|
|
- [x] 8.2: Add new page via FAB
|
|
- [x] 8.3: NavGraph refactored — pages route loads notebook metadata then shows
|
|
PageListScreen, tap page navigates to editor with page size
|
|
|
|
### Phase 9: PDF Export (2026-03-24)
|
|
|
|
- [x] 9.1: PdfExporter — creates PdfDocument, scales canonical 300 DPI coords
|
|
to 72 DPI PDF points (x0.24), renders strokes without grid
|
|
- [x] 9.2: Share via Intent.ACTION_SEND + FileProvider (configured in Phase 1)
|
|
- [x] 9.3: PDF button in editor toolbar, exports current page
|
|
|
|
### Phase 10: Polish (2026-03-24)
|
|
|
|
- [x] 10.1: High-contrast e-ink theme — expanded color scheme with proper
|
|
container, variant, and outline colors for readability
|
|
- [x] 10.2: Auto-save already in place since Phase 3 (strokes save on completion)
|
|
- [x] 10.3: Empty states and delete confirmations already in place from Phase 2
|
|
- [ ] 10.4: Performance profiling — requires on-device testing
|
|
|
|
### On-Device Testing — Daylight DC-1 (2026-03-24)
|
|
|
|
Tested on DC-1, identified and fixed rendering issues:
|
|
|
|
- **Grid**: original grid drawn in canonical space had uneven spacing due to
|
|
sub-pixel positioning when scaled. Fixed by drawing grid in screen space
|
|
with pixel-snapped line positions. Now uniform squares.
|
|
- **Stroke quality**: original backing bitmap at 1/4 resolution caused blurry
|
|
strokes. Fixed by switching to a screen-resolution backing bitmap with
|
|
incremental stroke addition. Anti-aliasing disabled on all paint for
|
|
crisp e-ink lines.
|
|
- **Viewport**: dark gray background was visible around page edges. Fixed by
|
|
clamping pan to page edges, computing dynamic min zoom, and white background.
|
|
- **Box tool**: works correctly on device.
|
|
- **PDF export**: correctly elides grid — confirmed on device.
|
|
- **Line snap**: increased threshold to 60pt (~5mm) and switched to max-distance
|
|
tracking to handle EMR stylus hand tremor.
|
|
|
|
### Code Audit & Bug Fixes (2026-03-24)
|
|
|
|
Critical/high-priority fixes applied:
|
|
- **MoveStrokesAction.undo()**: was offsetting by (0,0) instead of restoring
|
|
original positions. Fixed to write back the pre-move point data.
|
|
- **Stroke commit flicker**: backing bitmap was fully redrawn on each new
|
|
stroke. Fixed with incremental rendering — new strokes draw directly
|
|
onto the existing bitmap without clearing.
|
|
- **Selection state leak**: view-side selection wasn't cleared on page
|
|
navigation. Added `onPageNavigated` callback.
|
|
- **Initial page fallback**: if `initialPageId` isn't found in DB,
|
|
fall back to first page instead of showing blank canvas.
|
|
- **Arrow head Paint allocation**: preallocated reusable Paint object
|
|
instead of allocating per drawArrowHeads() call.
|
|
- **CopyStrokesAction**: fixed `takeLast(n)` fragile ID lookup — now
|
|
tracks copied stroke IDs directly.
|
|
- **Grid caching**: grid bitmap is now cached and only redrawn on
|
|
zoom/pan/resize changes.
|
|
|
|
### Post-Phase 10: Feature Polish (2026-03-24)
|
|
|
|
Extensive feature work after the initial 10-phase plan:
|
|
|
|
- **Toolbar redesign**: replaced FilterChip toolbar with icon-button toolbar.
|
|
Custom Canvas-drawn icons for each tool (pen dot, line, box outline,
|
|
eraser, dashed-rect select, four-way-arrow move, curved undo/redo arrows).
|
|
- **Pen size consolidation**: expanded from 2 sizes to 4 sizes (0.38mm,
|
|
0.5mm, 0.6mm, 0.7mm). Single PEN tool with long-press for size selection
|
|
dropdown; remembers last size.
|
|
- **Line tool**: dedicated LINE tool (separate from PEN) with style variants
|
|
via long-press menu: plain, arrow, double-arrow, dashed. Line style stored
|
|
in stroke `style` column in DB.
|
|
- **Box tool**: draws rectangles corner-to-corner. Uses current pen size
|
|
and style.
|
|
- **Move tool**: dedicated MOVE tool for tap-and-drag stroke relocation
|
|
(separate from select-then-drag).
|
|
- **Edge swipe navigation**: finger swipe from left/right screen edge
|
|
navigates to previous/next page. Auto-creates new page on forward swipe
|
|
past last page (if current page has strokes). Edge zone = 8% of screen
|
|
width, minimum 100px horizontal distance.
|
|
- **Page list drag-to-reorder**: long-press drag in PageListScreen to
|
|
reorder pages. Uses `longPressDraggableHandle` with reorderable lazy
|
|
column. Page numbers renumbered sequentially on drop.
|
|
- **Notebook rename**: long-press notebook in library list to rename.
|
|
Rename dialog with text field.
|
|
- **Library filter/sort**: search field to filter notebooks by title,
|
|
sort by last-edited or title (ascending/descending).
|
|
- **JPG export**: single-page JPEG export at 300 DPI via Export dropdown
|
|
menu. Uses `Bitmap.compress(JPEG, 95)`, shared via FileProvider + intents.
|
|
- **Clipboard operations**: cut, copy, paste toolbar buttons appear when
|
|
strokes are selected or clipboard is non-empty. Cut = copy + delete.
|
|
- **Startup state restoration**: SharedPreferences in EngPadApp store last
|
|
opened notebook ID and view-all-pages flag. On launch, auto-navigates to
|
|
last notebook (or page list if that was the last screen).
|
|
- **Page navigation from editor**: binder button in toolbar shows
|
|
"p1/5"-style page indicator with dropdown for "View all pages" and
|
|
"Go to page..." dialog.
|
|
- **Last page tracking**: Notebook entity has `lastPageId` column; editor
|
|
resumes at last-visited page when reopening a notebook.
|
|
- **Page delete**: delete pages from PageListScreen with sequential
|
|
renumbering of remaining pages.
|
|
- **Database migrations**: schema at version 3 (added `style` column to
|
|
strokes, `last_page_id` to notebooks).
|
|
|
|
## Backup Design (Not Yet Implemented)
|
|
|
|
Notebook backup as a zip file:
|
|
- Export: `notebook_title.engpad.zip` containing:
|
|
- `notebook.json` — notebook metadata (title, page_size, page count)
|
|
- `pages/` directory with one JSON per page:
|
|
- `pages/001.json` — page metadata + strokes array
|
|
- Each stroke: `{penSize, color, style, points: [x0,y0,x1,y1,...]}`
|
|
- Points stored as JSON float arrays (portable, human-readable)
|
|
- Import: parse zip, create notebook + pages + strokes in DB
|
|
- Could be shared via Android share intents like PDF/JPG export
|
|
- Consider: export all notebooks as a single zip for full backup,
|
|
or individual notebook export for sharing
|
|
|
|
Alternative: SQLite `VACUUM INTO` for raw DB backup (simpler but not
|
|
portable or human-readable).
|
|
|
|
## Status
|
|
|
|
All implementation phases complete. Post-phase polish significantly extended
|
|
the feature set beyond the original plan. Remaining work:
|
|
- Test on Supernote Manta
|
|
- Performance profiling with heavily annotated pages
|
|
- Implement notebook backup/restore (zip format)
|
|
- Server sync integration (eng-pad-server, gRPC, manual sync)
|
|
|
|
## Decisions & Deviations
|
|
|
|
- **Language**: Kotlin (chosen over Java for better Compose/coroutine support).
|
|
- **Storage**: Room/SQLite with packed float BLOBs for stroke points.
|
|
- **Palm rejection**: Hardware only (EMR digitizer handles it).
|
|
- **Pressure sensitivity**: None — four pen sizes (0.38, 0.5, 0.6, 0.7mm).
|
|
- **Coordinate system**: 300 DPI canonical points (scaled to 72 DPI for PDF export).
|
|
- **UI framework**: Compose for chrome, custom View for canvas (Compose
|
|
Canvas lacks MotionEvent access needed for stylus input).
|
|
- **Toolbar**: Icon buttons with Canvas-drawn icons (no drawable resources needed
|
|
for tool icons). Long-press for sub-menus (pen size, line style).
|
|
- **Rendering**: Screen-resolution backing bitmap with incremental stroke
|
|
addition + cached grid bitmap. Both invalidated on zoom/pan/resize.
|
|
- **Line styles**: Stored as string in stroke `style` DB column (plain, dashed,
|
|
arrow, double_arrow) rather than a separate table.
|
|
- **State restoration**: SharedPreferences for last notebook/page rather than
|
|
Compose SavedStateHandle (survives process death).
|