- 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>
6.7 KiB
6.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
eng-pad is an Android note-taking app built around notebooks with an EMR pen as the primary input method. Target devices are the Supernote Manta (Android 11) and Daylight DC-1 (Android 13). Minimum API level is Android 11 (API 30).
Build Commands
make all # lint -> test -> build
make build # Compile debug + release APKs
make test # Run unit tests
make lint # Run Android Lint
make clean # Clean build artifacts
make apk # Build release APK
make run # Build, install, and launch on emulator (starts emulator if needed)
make devrun # Build, install, and launch on connected USB device
make run AVD=Medium_Phone_API_36.0 # Use a specific AVD
# Run a single test class:
make test-one CLASS=net.metacircular.engpad.data.StrokeBlobTest
# Direct Gradle commands:
./gradlew build # Compile + test + lint
./gradlew test # Unit tests only
./gradlew lint # Android Lint only
Architecture
- Kotlin + Jetpack Compose for UI chrome (screens, toolbar, dialogs)
- Custom View (
PadCanvasView) for the drawing canvas — Compose Canvas lacksMotionEventaccess needed for stylus input - Room (SQLite) for persistence — notebooks, pages, strokes (schema version 3)
- SharedPreferences for startup state restoration (last notebook, page list flag)
- Single Activity with Compose Navigation (three routes: notebook list -> page list -> editor)
- Coordinate system: 300 DPI canonical points. Regular page = 2550x3300pt, large = 3300x5100pt. Scaled to 72 DPI (x0.24) for PDF export.
- Input dispatch:
TOOL_TYPE_STYLUS-> draw/erase/select/move,TOOL_TYPE_FINGER-> zoom/pan/edge swipe
Project Documents
- DESIGN.md — Full technical design (architecture, data model, rendering, tools, source tree)
- PROJECT_PLAN.md — All implementation steps with checkboxes. Check off steps as completed.
- PROGRESS.md — What's been done, what's in progress, decisions made. Update after every step.
Keep PROJECT_PLAN.md and PROGRESS.md in sync. When a step is completed, check it off in PROJECT_PLAN.md and log it in PROGRESS.md. When files are added, update the source tree in both DESIGN.md and this file.
Source Tree
eng-pad/
├── app/
│ ├── build.gradle.kts -- Module build config
│ └── src/
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin/net/metacircular/engpad/
│ │ │ ├── EngPadApp.kt -- Application class, SharedPreferences
│ │ │ ├── MainActivity.kt -- Single activity, Compose NavHost
│ │ │ ├── data/
│ │ │ │ ├── db/ -- Room database (v3), DAOs, converters
│ │ │ │ ├── model/ -- Entities: Notebook, Page, Stroke, PageSize
│ │ │ │ └── repository/ -- NotebookRepository, PageRepository
│ │ │ ├── ui/
│ │ │ │ ├── navigation/NavGraph.kt -- Routes, auto-restore last notebook
│ │ │ │ ├── notebooks/ -- Library: list, filter, sort, rename + ViewModel
│ │ │ │ ├── pages/ -- Page grid, drag-to-reorder + ViewModel
│ │ │ │ ├── editor/ -- PadCanvasView, EditorScreen, ViewModel, Toolbar
│ │ │ │ ├── export/PdfExporter.kt -- PDF + JPG generation + sharing
│ │ │ │ └── theme/Theme.kt -- Material3 high-contrast e-ink theme
│ │ │ └── undo/ -- UndoManager, UndoableAction, StrokeActions, SelectionActions
│ │ └── res/
│ │ ├── values/ -- strings.xml, themes.xml
│ │ ├── drawable/ -- Launcher icons
│ │ ├── mipmap-anydpi/ -- Adaptive icon
│ │ └── xml/file_provider_paths.xml -- FileProvider config
│ └── test/ -- Unit tests (StrokeBlobTest, PageSizeTest, UndoManagerTest)
├── build.gradle.kts -- Root build config
├── settings.gradle.kts -- Project settings (foojay JDK resolver)
├── gradle.properties
├── gradle/libs.versions.toml -- Version catalog
├── Makefile -- Build targets (build, test, lint, run, devrun, apk)
├── CLAUDE.md -- This file
├── README.md
├── DESIGN.md -- Technical design
├── PROJECT_PLAN.md -- Implementation steps
└── PROGRESS.md -- Completion tracking
Key Conventions
- Stroke points are packed as little-endian float BLOBs:
[x0,y0,x1,y1,...] - All coordinates are in canonical space (300 DPI). Screen transform via
Matrix. - Grid drawn in screen space with pixel-snapped positions (not canonical space) for uniform squares. Cached in a grid bitmap, redrawn only on zoom/pan/resize.
- 4 pen sizes: 0.38mm (4.49pt), 0.5mm (5.91pt), 0.6mm (7.09pt), 0.7mm (8.27pt) at 300 DPI.
- Single PEN tool with long-press for size selection; remembers last size.
- Line styles stored in stroke
styleDB column: plain, dashed, arrow, double_arrow. - LINE tool with long-press for style selection; BOX tool for rectangles.
- MOVE tool for tap-and-drag stroke relocation.
- Anti-aliasing disabled on all paint objects for crisp e-ink rendering.
- Screen-resolution backing bitmap with incremental stroke addition (no full redraw on each new stroke).
- Viewport: page always fills screen, pan clamped to edges, dynamic min zoom.
- Edge swipe navigation: finger swipe from screen edge -> previous/next page.
- Line snap: hold pen still 1.5s to snap to straight line (60pt movement threshold).
- Hardware palm rejection only (EMR digitizer).
- Startup state restoration via SharedPreferences (last notebook ID, page list flag).
- Notebook
lastPageIdtracks resume position per-notebook. - Clipboard: cut/copy/paste with toolbar buttons shown contextually.
- Export: PDF (multi-page, 72 DPI) and JPG (single page, 300 DPI) via share intents.