You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,8 +38,8 @@ EasyWatermark (`me.rosuh.easywatermark`) — a privacy-focused Android app that
38
38
- **iOS watermark editor — first off-Android consumer of the shared watermark editor (S4d-102..S4d-113, accepted):** the iOS app now edits/persists watermark text, degree, tileMode, alpha, textColor, textSize, h/v gaps, textTypeface, and textStyle through the common `WaterMarkRepository` + `WatermarkConfigEditor` via the Swift-facing `IosWatermarkConfigBridge` (suspend value APIs only; no `Flow`/`DataStore` in public Swift signatures). The bridge supplies off-Android repo edges with platform-neutral iOS values: default text `"EasyWatermark 水印"`, pure `WatermarkTileMode.fromStorageId` (Android SDK-gated DECAL-id-3 migration does not apply off-Android), and simple logging. S4d-107/109/110 aligned fresh iOS renders to shared defaults for color `#FFB800`, text size `14`, and gaps `0/0`; S4d-112 added iOS Skiko render-edge honoring for `TextTypeface`; S4d-113 wired `TextPaintStyle` through the iOS edge. S4d-122 exposed the remaining commonMain paint gap, and **S4d-123 fixed it by passing `TextStyle.drawStyle` to `MultiParagraph.paint`**; `Stroke` is now raster-honored on Desktop/iOS Skiko, while Android text production remains native. This is build/runtime proof of editor state flow, NOT final Android v2.10.0 1:1 visual parity; real PHPicker grid-cell selection remains the pre-existing beta-toolchain limitation. The text-field lane is exhausted; `iconUri`/`markMode` is a separate mini-epic, and `enableBounds` stays deferred.
39
39
- **Desktop app-entry `UserConfigRepository` wiring (S4d-80, accepted 2026-06-27, commit `3daa7c4`):** `desktopApp` `Main.kt` now constructs `UserConfigRepository(createUserConfigDataStore(dir = File("build/s4d80-desktop-userconfig")))` and proves read → `updateFormat(PNG)` + `updateCompressLevel(60)` → read via `runBlocking { userPreferences.first() }`, verified by `:desktopApp:run` (printed initial `(JPEG, 80)` then `(PNG, 60)`; a second run showed initial `(PNG, 60)` → on-disk persistence across runs). This is the **first app-entry (non-test) use of the common prefs repo** — an **app-level smoke/witness**, NOT the real Compose Desktop editor consuming prefs (C4) and NOT 1:1 UI/UX parity. `desktopApp/build.gradle.kts` declares the existing catalog aliases `libs.kotlin.coroutine.core` + `libs.datastore.preference` (NO new dependency version) because `:desktopApp` directly consumes `:shared`'s public-API types (`Flow`, `DataStore<Preferences>`), which `:shared` exposes as `implementation` (so they don't transit — `:app` declares them likewise). Desktop-only: Android/`:shared`/iOS/renderer/Room/Koin/goldens untouched.
40
40
- **Desktop minimal product flow (S4d-119 readiness -> S4d-130, accepted 2026-06-27):** S4d-119 proved `:desktopApp` was still a CLI witness and selected the smallest non-speculative Desktop product-flow path. S4d-120 added desktop `createWaterMarkDataStore(...)`, a Desktop `WaterMarkRepository`/`WatermarkConfigEditor` roundtrip test, and a headless **open -> edit -> render -> save** flow writing `desktopApp/build/s4d120-desktop-headless/watermarked.png` (or CLI output path). S4d-121 added the minimal Compose Desktop `Window`: no-arg `:desktopApp:run` opens `EasyWatermark — Desktop (S4d-121)` and the sample button runs the same save spine; `--headless` remains the bounded automation path. **S4d-122 made Desktop text rendering and `composeOverRealImage` consume persisted `WaterMark.textColor` + `TextTypeface`** (color now defaults to shared amber `WaterMark.default.textColor`, and typeface maps to Compose `FontWeight`/`FontStyle`) and passed `TextPaintStyle` through. **S4d-123 completed shared drawStyle threading**, so `TextPaintStyle.Stroke` is raster-honored on Desktop/iOS Skiko; Android text production remains native. **S4d-124 selected the next Desktop slice, and S4d-125 added the first interactive file input:** the Desktop window now has an **"Open image..."** button using native JDK/AWT `FileDialog` to pick a real image, read bytes off the UI thread, and call the existing `DesktopWatermarkFlow.runSaveFlow(inputBytes, inputLabel)` spine. Cancel is a no-op; `--headless` stays unchanged. **S4d-126/S4d-130 split output-format safely:** S4d-127 added the Desktop encoder primitive (`ImageFormat.PNG` byte-identical `encodePng`; `ImageFormat.JPEG` ARGB -> opaque RGB flatten + JDK `ImageIO` quality), with `composeOverRealImage` still defaulting PNG for composer goldens. S4d-128 then wired the Desktop save spine to `UserConfigRepository.userPreferences.first()`: empty Desktop stores now follow shared/Android defaults (`JPEG/80`) and default output paths become format-aware (`watermarked.jpg` or `watermarked.png`), while PNG remains available when prefs select PNG. S4d-130 added the minimal window selector: two preset buttons (`JPEG / 80`, `PNG / 100`) write through the shared `OutputPrefsEditor` over the same store the save flow reads. **Still not a full Desktop editor and not 1:1 parity:** no drag/drop, interactive image preview, templates, share substitute, icon watermark, arbitrary quality selector, or final Android v2.10.0 UI parity.
41
-
- **Desktop product-flow continuation (S4d-132 -> S4d-143b, accepted 2026-06-27/28):** S4d-132..S4d-137 completed the Desktop icon/source mini-epic at functional-code level: icon composition primitive, persisted Image-mode save branch, "Open icon...", "Use text watermark", and remembered source-image reuse. S4d-138/S4d-140 then added the release-code map, `DesktopSaveDecision` harness, and destination-only "Save as..." control. **S4d-141..S4d-143b closed the first templates persistence lane:** Desktop has an empty-store Room builder (`buildTemplateDatabase(dir)` with `BundledSQLiteDriver`), a `:desktopApp --headless` TemplateRepository/TemplateEditor witness, and a read-only proof that both Android seed DBs match generated Room identity hash `72366f557b971b39675d0f26cbc46e0a`. **S4d-224 (accepted 2026-06-29, commit `c7959d0`) implemented the Desktop English template seed** via a `:shared` desktopMain resource + `TemplateDatabaseSeeds.unpackDefaultTemplateSeed` + `buildTemplateDatabase(dir, seedFile)` (direct seed-file copy because Room KMP off-Android does not expose `createFromFile`/`createFromAsset`). **S4d-225 (accepted 2026-06-29, commit `875b105`) made that seeding locale-aware** (`ewm-db-ch.db` for `zh` JVM locales, `ewm-db-eng.db` otherwise). **Still not a full Desktop editor and not 1:1 parity:** no full Android-equivalent editor/polish, template edit-in-place, batch, arbitrary quality selector, or final Android v2.10.0 UI parity.
42
-
- **Desktop window controls + share substitute + drag/drop + templates UI (S4d-145 -> S4d-160, accepted 2026-06-28):** Desktop window enrichment stayed one-file and functional: manual watermark text control, preview output, degree/color/opacity/gap/text-size/tile/typeface/style controls, scrolling, a no-new-dependency share substitute, dropped-image input, and a minimal Templates section. The share substitute tracks only the last successful real save from Render & Save / Save as / Open image / image drop; Preview temp output is deliberately not share state. Drag/drop uses Compose Desktop `dragAndDropTarget` + AWT file-list flavor and reuses the Open-image save spine. **S4d-159** chose templates UI over reactive preview because `Template.content` is just watermark text; reactive preview would reverse the deliberate manual-preview contract. **S4d-160** added Save current text / list / Use / Delete over `buildTemplateDatabase(dir)` + `TemplateRepository` + `TemplateEditor`; Use applies via `WatermarkConfigEditor.updateText`. **S4d-224 then added Desktop template default seeding** from the English Android seed DB via a `:shared` desktopMain resource + helper, and **S4d-225 made it locale-aware** (`ewm-db-ch.db` for `zh` JVM locales, `ewm-db-eng.db` otherwise). **Still not 1:1 parity:** template edit-in-place, batch, and final Android v2.10.0 screenshot/recording parity remain separate gates.
41
+
- **Desktop product-flow continuation (S4d-132 -> S4d-143b, accepted 2026-06-27/28):** S4d-132..S4d-137 completed the Desktop icon/source mini-epic at functional-code level: icon composition primitive, persisted Image-mode save branch, "Open icon...", "Use text watermark", and remembered source-image reuse. S4d-138/S4d-140 then added the release-code map, `DesktopSaveDecision` harness, and destination-only "Save as..." control. **S4d-141..S4d-143b closed the first templates persistence lane:** Desktop has an empty-store Room builder (`buildTemplateDatabase(dir)` with `BundledSQLiteDriver`), a `:desktopApp --headless` TemplateRepository/TemplateEditor witness, and a read-only proof that both Android seed DBs match generated Room identity hash `72366f557b971b39675d0f26cbc46e0a`. **S4d-224 (accepted 2026-06-29, commit `c7959d0`) implemented the Desktop English template seed** via a `:shared` desktopMain resource + `TemplateDatabaseSeeds.unpackDefaultTemplateSeed` + `buildTemplateDatabase(dir, seedFile)` (direct seed-file copy because Room KMP off-Android does not expose `createFromFile`/`createFromAsset`). **S4d-225 (accepted 2026-06-29, commit `875b105`) made that seeding locale-aware** (`ewm-db-ch.db` for `zh` JVM locales, `ewm-db-eng.db` otherwise). **S4d-226 (accepted 2026-06-29, commit `1fa945f`) added the minimal row-level template update action** (Update button → `TemplateEditor.update`, preserving id/creationDate, enabled only for nonblank current text). **Still not a full Desktop editor and not 1:1 parity:** no full Android-equivalent editor/polish, batch, arbitrary quality selector, or final Android v2.10.0 UI parity.
42
+
- **Desktop window controls + share substitute + drag/drop + templates UI (S4d-145 -> S4d-160, accepted 2026-06-28):** Desktop window enrichment stayed one-file and functional: manual watermark text control, preview output, degree/color/opacity/gap/text-size/tile/typeface/style controls, scrolling, a no-new-dependency share substitute, dropped-image input, and a minimal Templates section. The share substitute tracks only the last successful real save from Render & Save / Save as / Open image / image drop; Preview temp output is deliberately not share state. Drag/drop uses Compose Desktop `dragAndDropTarget` + AWT file-list flavor and reuses the Open-image save spine. **S4d-159** chose templates UI over reactive preview because `Template.content` is just watermark text; reactive preview would reverse the deliberate manual-preview contract. **S4d-160** added Save current text / list / Use / Delete over `buildTemplateDatabase(dir)` + `TemplateRepository` + `TemplateEditor`; Use applies via `WatermarkConfigEditor.updateText`. **S4d-224 then added Desktop template default seeding** from the English Android seed DB via a `:shared` desktopMain resource + helper, **S4d-225 made it locale-aware** (`ewm-db-ch.db` for `zh` JVM locales, `ewm-db-eng.db` otherwise), and **S4d-226 added the row-level template update action** (Update button → `TemplateEditor.update`, preserving id/creationDate). **Still not 1:1 parity:** batch and final Android v2.10.0 screenshot/recording parity remain separate gates.
43
43
- **Desktop reactive preview (S4d-198, accepted 2026-06-28, commit `1f0019b5`, `DesktopWindow.kt` only):** the blind-edit "click Preview to see it" loop is **gone** — a successful explicit editor/mode action now **auto-refreshes** the on-screen preview. One extracted local helper `refreshPreview()` drives the 6 Apply fields (text/degree/color/opacity/gaps/text-size), tile REPEAT/CLAMP, typeface, text-style, the "Use text watermark" (→Text) and "Open icon…" (→Image) mode flips, **template Use**, and the **Open image… / image drop** source changes — all through the SAME `DesktopWatermarkFlow.runSaveFlow` → `DesktopImageDecoder` temp-file spine the manual `Preview` button uses (which now just calls the helper; the duplicated inline render was removed). **Bounded** to explicit clicks / source-load events (NOT per keystroke — `onValueChange` untouched). Preview writes ONLY `build/s4d147-desktop-preview/preview.img` and **never** sets `lastSavedFile` (share-substitute stays real-save-bound); a refresh failure keeps the last good preview. "Render & Save sample" / "Save as…" remain real-save-only; Open image / drop still set `lastImage`+`lastSavedFile` from their real save, with the added refresh gated on real-save success. Functional Desktop product-flow, **not** 1:1 parity. (S4d-198b is the docs closeout.)
44
44
- **Desktop persistence/output/icon now use user storage, with the icon copy in a tested `shared/desktopMain` helper (`:shared:desktopTest`) (S4d-215 -> S4d-221, accepted 2026-06-28/29):** the interactive Desktop window persists its state under the stable per-user dir `~/.easywatermark` (watermark config + output prefs + templates Room DB — S4d-215), writes real saves (drop / Render & Save / Open image) to a user output dir (`~/Pictures` else `~/.easywatermark/output` — S4d-217), and on "Open icon…" copies the picked icon into app-private `~/.easywatermark/watermark_icons/icon.<ext>` persisting THAT copy path (S4d-219) — instead of repo-local `build/` dev paths or the user's original icon path. **S4d-221 (commit `1fe8ab9e`) extracted the S4d-219 copy-then-prune logic out of `DesktopWindow.kt` into a tested `shared/desktopMain` helper `DesktopIconPersistence.persistIcon(source, iconsDir)`** (verbatim semantics — same-copy no-op via `canonicalFile`, copy -> `incoming.tmp` -> atomic `Files.move(ATOMIC_MOVE, REPLACE_EXISTING)`, prune others only after the target exists -> bounded one file, throws so the prior copy survives a failed source read), now **CI-covered** by `DesktopIconPersistenceTest` (`:shared:desktopTest`, 5/0) — parity with the tested iOS `IosIconPersistence` (S4d-116). `DesktopWindow.kt` now just wires the UI to the helper (`IMAGE_EXTENSIONS` filter, mode→Image flip, S4d-198 preview refresh, and `try/catch → "Failed: …"` status unchanged). **Intentionally unchanged (do NOT "fix"):** `DesktopWatermarkFlow` build-local defaults + `Main.kt` headless/demo witness + the preview temp stay build-local by design. **S4d-222 (accepted 2026-06-29, commit `0eaafdd5`)** added collision-avoiding default save filenames: the three default-name real-save sites (image drop, Render & Save sample, Open image) now call `DesktopSaveDecision.resolveUniqueOutputFile(outputDir, fmt)` (shared `desktopMain`), producing `watermarked.<ext>` if free else the smallest `watermarked_n.<ext>` suffix; `Save as…` (user-chosen path), preview temp, headless/demo, and `DesktopWatermarkFlow` defaults stay build-local by design. Tested in `:shared:desktopTest` (`DesktopSaveDecisionTest`, 6 new cases, 11/0 total). Release-grade Desktop save safety, **not** Android v2.10.0 1:1 parity; the GUI icon-picker click stays a thin manual/UI-wiring acceptance path (the copy/prune correctness is now unit-tested).
45
45
- **Desktop release hygiene + packaging proof (S4d-161 -> S4d-166, accepted 2026-06-28):** S4d-161 (read-only decision) chose release-grade hygiene + a packaging proof over speculative UI widening. **S4d-162** (commit `bb5e770f`, `DesktopWindow.kt` only) made the window title release-facing (`EasyWatermark — Desktop`, dropping the `(S4d-121)` dev marker) and disabled the Templates "Save current text" button when the watermark text is blank. **S4d-163** (commit `ccc9f3f7`, `desktopApp/build.gradle.kts` only) replaced the plain Gradle `application` plugin with the Compose Desktop `compose.desktop { application { mainClass; nativeDistributions { packageName = "EasyWatermark"; packageVersion = "1.0.0" } } }` DSL, so the packaging tasks now exist (`createDistributable`/`runDistributable`/`packageDistributionForCurrentOS`) and `createDistributable` builds an **unsigned `.app` image** (native launcher + `Info.plist` + bundled JRE + app jars, under `desktopApp/build/compose/binaries/main/app/`). The `run` task moved into the Compose DSL and `:desktopApp:run --args='--headless'` still works (witnesses unchanged). **JDK caveat:** `createDistributable` **fails** under the jenv/Homebrew OpenJDK because Compose Desktop's `checkRuntime` rejects Homebrew vendors (CMP issue #3107); it **succeeds** with the already-installed Amazon Corretto 17 (`/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home`). The accepted path is to use a **supported packaging JDK** — do **NOT** add `compose.desktop.packaging.checkJdkVendor=false`. **S4d-166** adds `.github/workflows/desktop_packaging.yml`, a narrow `workflow_dispatch` + path-filtered PR job using Ubuntu + Zulu 17 that runs `:desktopApp:run --args='--headless'` before `:desktopApp:createDistributable`; the green Actions run is the proof that Zulu satisfies the vendor guard. **Overclaim guard:** unsigned app-image proof/workflow ONLY — no installer formats (DMG/PKG/MSI/DEB), signing/notarization, app icon, real product-version source yet (`packageVersion = "1.0.0"` is a placeholder), macOS packaging, or Android v2.10.0 1:1 UI/UX parity.
0 commit comments