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: docs/CONTEXT.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ Domain vocabulary and invariants. Agents and humans: use these words with these
30
30
|**iOS Swift bridge retention**|**S4d-82 (accepted 2026-06-27, commit `98e13d9`)** — `iosApp/iosApp/WatermarkWorkflow.swift` retains one `IosUserConfigBridge` via `IosUserConfigBridgeKt.defaultIosUserConfigBridge()`; `loadUserConfigWitness()` calls `try await currentPreferences()` once on launch (read-only; `ContentView``.task` triggers it) and stores a **non-visible**`@Published private(set) userConfigWitness` (not in any View body). **Link/async-interop witness only — no prefs/settings UI, no 1:1 parity.** Build-proven on the generic iOS Simulator SDK (`xcodebuild ... BUILD SUCCEEDED`). Two existing Swift files only (no new file / `project.pbxproj`); the S4d-81 Kotlin bridge is unchanged. Future prefs UI should replace this witness with real state usage. |
31
31
| **iOS watermark-config bridge (first off-Android editor consumer)** | **S4d-102..S4d-118 (accepted 2026-06-27)** — the iOS app edits + persists watermark text, degree, tileMode, alpha, textColor, textSize, h/v gaps, textTypeface, and textStyle through the common `WaterMarkRepository` + `WatermarkConfigEditor`. `shared/src/iosMain/.../data/datastore/CreateDataStore.ios.kt` adds `createWaterMarkDataStore(name = WaterMarkRepository.SP_NAME)` (NSDocumentDirectory, mirroring `createUserConfigDataStore`); `IosWatermarkConfigBridge` exposes only suspend value APIs to Swift (no `Flow`/`DataStore`), with writes routed through `WatermarkConfigEditor`. iOS repo edges are platform-neutral: default text `"EasyWatermark 水印"`, the **pure** `WatermarkTileMode.fromStorageId` (the Android SDK-gated legacy tile migration does **not** apply off-Android), `println` logging; **no new dependency**. S4d-107/109/110 aligned fresh iOS renders to shared defaults for amber `#FFB800`, text size `14`, and gaps `0/0`; S4d-112 made iOS Skiko text consume `TextTypeface`; S4d-113 wired `TextPaintStyle`; **S4d-123 fixed the commonMain drawStyle paint gap found in S4d-122**, so `Stroke` is raster-honored on Desktop/iOS Skiko while Android text production remains native. **Build/runtime proof of the editor state flow — NOT 1:1 parity**. **S4d-114 accepted the `iconUri`/`markMode` decision pack; S4d-115 landed the Kotlin-only iOS icon render foundation**: `IosWatermarkRenderer.renderIconCell` wraps commonMain `composeIconCell`, and `composeIconOverImage` decodes background+icon bytes via `IosImageDecoder` then composes through `composeOverBackground`. The icon cell is rendered opaque and alpha is applied once at composition; this is perceptual iOS/Skiko behavior, not Android native byte parity. **S4d-116 added durable iOS icon-byte persistence:** `IosIconPersistence` copies bytes to app-private `NSDocumentDirectory/watermark_icons/icon_<NSUUID>`, `IosWatermarkConfigBridge.setIconFromBytes` persists `MediaRef(path)` through `WatermarkConfigEditor.updateIcon` (flipping Image mode), and cleanup rejects traversal/nested suffixes before deletion. **S4d-117 wired the iOS render branch:** Text mode still uses the existing text bridge; Image mode reads icon bytes through `IosWatermarkConfigBridge.currentIconBytes()` and renders via `IosWatermarkRenderBridge.renderIconWatermarkedPng`; missing/unreadable icon fails visibly. **S4d-118 wired the minimal picker UI:** a separate SwiftUI icon `PhotosPicker` passes picked bytes to `setIconFromBytes`, shows Text/Image mode plus a transient thumbnail, and re-renders the current source image. Real PHPicker grid-cell automation remains S4d-57-limited; `enableBounds` remains deferred. |
32
32
| **Desktop prefs/headless flow** | **S4d-80 (accepted 2026-06-27, commit `3daa7c4`)** was the first app-entry (non-test) use of the common prefs repo: `desktopApp` constructs `UserConfigRepository(createUserConfigDataStore(dir = File("build/s4d80-desktop-userconfig")))` and proves read → `updateFormat(PNG)`/`updateCompressLevel(60)` → read via `runBlocking`. **S4d-119** then mapped the Desktop product-flow gaps and selected a no-new-dependency headless save slice before any Compose Desktop window. **S4d-120 (accepted, commit `7583099`)** added desktop `createWaterMarkDataStore`, a `WaterMarkRepository`/`WatermarkConfigEditor` roundtrip test, and a `desktopApp` headless open → edit → render → save flow that persists a watermark config, re-reads it, feeds the honored fields into `DesktopWatermarkComposer.composeOverRealImage`, and writes `build/s4d120-desktop-headless/watermarked.png`. **S4d-121 (accepted, commit `6c4ffdd`)** added the minimal Compose Desktop `Window`: no-arg `:desktopApp:run` opens `EasyWatermark — Desktop (S4d-121)`, while `--headless` keeps the bounded console/save automation. **S4d-122 (accepted, commit `4e4d928`)** made Desktop text rendering / real-image composition consume persisted `WaterMark.textColor` + `TextTypeface` (raster-honored; color default now shared amber) and pass `TextPaintStyle` through. **S4d-123 (accepted, commit `2ec876d`)** fixed commonMain drawStyle painting, so `TextPaintStyle.Stroke` is raster-honored on Desktop/iOS Skiko. **S4d-125** added the first interactive file input: the Desktop window's **"Open image..."** button uses native JDK/AWT `FileDialog`, reads selected bytes on `Dispatchers.IO`, and routes them through `DesktopWatermarkFlow.runSaveFlow(inputBytes, inputLabel)`; cancel is a no-op and `--headless` remains unchanged. **S4d-126/S4d-130** split Desktop output-format safely: S4d-127 added `DesktopWatermarkTextRenderer.encode(bitmap, format, quality)` with PNG byte-identical passthrough and JPEG alpha-flatten + JDK `ImageIO` quality while keeping `composeOverRealImage(..., format = ImageFormat.PNG, quality = 100)` as the PNG-default composer/golden path. S4d-128 wired `DesktopWatermarkFlow.runSaveFlow` to `UserConfigRepository.userPreferences.first()`: fresh Desktop prefs now match shared/Android `(JPEG, 80)`, null output paths choose `watermarked.jpg`/`watermarked.png` by effective format, and PNG remains available when prefs select PNG. S4d-130 added a minimal Desktop window selector: `JPEG / 80` and `PNG / 100` preset buttons persist via the shared `OutputPrefsEditor` over the same `UserConfigRepository` the save flow reads. **Still not the full Compose 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 yet. |
33
-
| **Desktop window controls/share substitute/drag-drop/templates UI** | **S4d-145..S4d-160 (accepted 2026-06-28)** widened the Desktop window through small one-file slices: watermark text editing, preview output, degree, color, opacity, h/v gaps, text size, tile mode, typeface/style, scrolling, share substitute, dropped-image input, and minimal templates UI. **S4d-157** added the selected no-new-dependency share substitute: only successful real saves update `lastSavedFile`, so Render & Save / Save as / Open image outputs can be shown in their folder or copied as a path; Preview temp output is deliberately excluded. **S4d-158** added Compose Desktop `dragAndDropTarget` over the existing Open-image save spine: dropped local image files are filtered by the same extension set, read on IO, saved through `DesktopWatermarkFlow.runSaveFlow`, and update `lastImage` plus successful-save `lastSavedFile`. **S4d-159/S4d-160** chose and added the minimal Templates section: Save current text / list / Use / Delete over `buildTemplateDatabase(dir)` + `TemplateRepository` + `TemplateEditor`; Use applies text through `WatermarkConfigEditor.updateText`. **S4d-198 (accepted 2026-06-28, commit `1f0019b5`)** then added **reactive preview**: a successful explicit editor/mode action (the 6 Apply fields, tile/typeface/style, the Use-text/Open-icon mode flips, template Use) **and** Open image / drop source changes now auto-refresh the on-screen preview via one `refreshPreview()` helper over the SAME `runSaveFlow` → `DesktopImageDecoder` temp-file spine the manual `Preview` button uses — bounded to explicit clicks/source events (not per-keystroke); preview writes only the temp file and never sets `lastSavedFile` (share-substitute stays real-save-bound); Render & Save / Save as stay real-save-only. This is functional Desktop product-flow coverage, not Android v2.10.0 UI/UX parity. Remaining Desktop gates include template edit-in-place/default seeding, batch, and final screenshot/recording parity after release-grade migration. **S4d-215 (accepted 2026-06-28, commit `873dbcbd`, `DesktopWindow.kt` only)** made the interactive window persist its user state — watermark config, output prefs, and the templates Room DB — under the stable per-user dir `~/.easywatermark` (new same-file helper `resolveDesktopAppDataDir()`, matching the `CreateDataStore.desktop.kt` convention; `user.home`-null falls back to a repo-local `build/` dir with a warning, no crash) instead of the old repo-local `build/` dev paths. **Intentionally unchanged (do NOT "fix"):** `DesktopWatermarkFlow` build-local *defaults* and `Main.kt`'s headless/demo witness paths stay build-local by design, and the transient preview temp stays `build/s4d147-desktop-preview/preview.img`. Runtime-proven: a window launch creates `~/.easywatermark/ewm-db` (templates DB) and no `build/s4d160-desktop-templates`; the two DataStore preference files (`sp_water_mark_config`, `sp_water_mark_user_config`) are written **lazily on first GUI edit**, so they are diff-proven + left as a manual GUI acceptance check (type text → save template → restart-persistence), not an automated proof. Release-grade Desktop persistence correctness, **not** 1:1 parity; default-template seeding remains deferred/owner-priority-gated. |
33
+
| **Desktop window controls/share substitute/drag-drop/templates UI** | **S4d-145..S4d-160 (accepted 2026-06-28)** widened the Desktop window through small one-file slices: watermark text editing, preview output, degree, color, opacity, h/v gaps, text size, tile mode, typeface/style, scrolling, share substitute, dropped-image input, and minimal templates UI. **S4d-157** added the selected no-new-dependency share substitute: only successful real saves update `lastSavedFile`, so Render & Save / Save as / Open image outputs can be shown in their folder or copied as a path; Preview temp output is deliberately excluded. **S4d-158** added Compose Desktop `dragAndDropTarget` over the existing Open-image save spine: dropped local image files are filtered by the same extension set, read on IO, saved through `DesktopWatermarkFlow.runSaveFlow`, and update `lastImage` plus successful-save `lastSavedFile`. **S4d-159/S4d-160** chose and added the minimal Templates section: Save current text / list / Use / Delete over `buildTemplateDatabase(dir)` + `TemplateRepository` + `TemplateEditor`; Use applies text through `WatermarkConfigEditor.updateText`. **S4d-198 (accepted 2026-06-28, commit `1f0019b5`)** then added **reactive preview**: a successful explicit editor/mode action (the 6 Apply fields, tile/typeface/style, the Use-text/Open-icon mode flips, template Use) **and** Open image / drop source changes now auto-refresh the on-screen preview via one `refreshPreview()` helper over the SAME `runSaveFlow` → `DesktopImageDecoder` temp-file spine the manual `Preview` button uses — bounded to explicit clicks/source events (not per-keystroke); preview writes only the temp file and never sets `lastSavedFile` (share-substitute stays real-save-bound); Render & Save / Save as stay real-save-only. This is functional Desktop product-flow coverage, not Android v2.10.0 UI/UX parity. Remaining Desktop gates include template edit-in-place/default seeding, batch, and final screenshot/recording parity after release-grade migration. **S4d-215 (accepted 2026-06-28, commit `873dbcbd`, `DesktopWindow.kt` only)** made the interactive window persist its user state — watermark config, output prefs, and the templates Room DB — under the stable per-user dir `~/.easywatermark` (new same-file helper `resolveDesktopAppDataDir()`, matching the `CreateDataStore.desktop.kt` convention; `user.home`-null falls back to a repo-local `build/` dir with a warning, no crash) instead of the old repo-local `build/` dev paths. **Intentionally unchanged (do NOT "fix"):** `DesktopWatermarkFlow` build-local *defaults* and `Main.kt`'s headless/demo witness paths stay build-local by design, and the transient preview temp stays `build/s4d147-desktop-preview/preview.img`. Runtime-proven: a window launch creates `~/.easywatermark/ewm-db` (templates DB) and no `build/s4d160-desktop-templates`; the two DataStore preference files (`sp_water_mark_config`, `sp_water_mark_user_config`) are written **lazily on first GUI edit**, so they are diff-proven + left as a manual GUI acceptance check (type text → save template → restart-persistence), not an automated proof. Release-grade Desktop persistence correctness, **not** 1:1 parity; default-template seeding remains deferred/owner-priority-gated. **S4d-217 (accepted 2026-06-28, commit `ce677bb2`, `DesktopWindow.kt` only)** then routed the window's REAL save *output* off the repo-local `build/` default: image **drop**, **Render & Save sample**, and **Open image…** now write to a user output dir — `~/Pictures` if that directory exists, else `~/.easywatermark/output` (`File(resolveDesktopAppDataDir(), "output")`) (new same-file helper `resolveDesktopOutputDir()`, created if missing) — passing `outputFile = File(outputDir, DesktopSaveDecision.defaultOutputFileName(fmt))` with `fmt = userConfigRepo.userPreferences.first().outputFormat`. **Unchanged by design:** `Save as…` still writes the user-chosen dialog path; the preview temp stays `build/s4d147-desktop-preview/preview.img`; and `DesktopWatermarkFlow` defaults + `Main.kt` headless/demo witness stay build-local (the `--headless` run still wrote `build/s4d120-desktop-headless/watermarked.jpg`). The output filename is fixed by format (`watermarked.jpg`/`.png`), so repeated real saves **overwrite** — collision-avoiding names remain deferred. Proof = compile + headless witness + diff/branch routing (on this host `~/Pictures` exists → that branch); the GUI save **click was not automated**, so the file actually landing in the user dir is a coordinator manual acceptance check, not a runtime-automated proof. Release-grade Desktop save-location correctness, **not** 1:1 parity. |
34
34
|**DynamicColorCapability**| Platform-neutral Material You gate (replaces direct `:cmonet`/`CMonet` in the live Compose consumers). **Landed (S4d-43, accepted 2026-06-25)** as `interface DynamicColorCapability { isAvailable(): Boolean; setForcedSupport(enabled: Boolean) }` in `shared/commonMain/.../platform`, bound as a Koin `single`. Android actual `AndroidDynamicColorCapability` delegates **verbatim** to unchanged `:cmonet` (same OEM allowlist + `dynamic_color_force` SP key); Desktop/iOS return `false` (static `Theme.kt` schemes are the fallback). Migrated consumers: `ComposeMainActivity``AppTheme` gate + About-route initial toggle state, `AboutViewModel` toggle write — these must **not** call `CMonet` directly anymore. `:cmonet` is **retained** behind the actual; `MyApp.init`, `ContextExtension` getters, and the logo path still use `:cmonet` directly (owner-gated absorption follow-up). |
35
35
|**ImageFormat (planned)**| App-owned export format enum (replaces `Bitmap.CompressFormat` in models/UI). JPEG honors quality (snapped to multiples of 20, min 20); PNG ignores it. |
36
36
|**Template**| Saved watermark text snippets (Room entity), prepopulated from locale-selected bundled DBs (`ewm-db-ch.db` / `ewm-db-eng.db`). |
Copy file name to clipboardExpand all lines: progress.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,13 @@
1
1
# Progress Log
2
2
3
+
## 2026-06-28 — S4d-217 Desktop window saves to user output dir accepted (+S4d-217b docs)
4
+
5
+
-**S4d-217 (implementation, accepted; commit `ce677bb2 Route Desktop saves to user output dir`, `DesktopWindow.kt` only, +34/-1):** the interactive Desktop window's three REAL save actions — image **drop**, **Render & Save sample**, and **Open image…** — now write the watermarked output to a user output dir instead of the repo-local `build/s4d120-desktop-headless` default. A new same-file helper `resolveDesktopOutputDir()` returns `~/Pictures` when that directory exists, else `~/.easywatermark/output` (`File(resolveDesktopAppDataDir(), "output")`), created if missing; `launchDesktopWindow()` remembers it, and each save passes `outputFile = File(outputDir, DesktopSaveDecision.defaultOutputFileName(fmt))` with `fmt = userConfigRepo.userPreferences.first().outputFormat` (the same value `runSaveFlow` reads → extension matches).
6
+
-**Intentionally unchanged (do NOT "fix"):**`Save as…` still writes the user-chosen dialog path; the preview temp stays `build/s4d147-desktop-preview/preview.img`; `DesktopWatermarkFlow` defaults + `Main.kt` headless/demo witness stay build-local (the `--headless` run confirmed it still wrote `build/s4d120-desktop-headless/watermarked.jpg`).
7
+
-**Verification:**`:desktopApp:compileKotlin` + `:desktopApp:run --args='--headless'` green (`--max-workers=8`, daemon stopped). On this host `~/Pictures` exists → `resolveDesktopOutputDir()` resolves to `~/Pictures`. The GUI save **click was not automated**, so the file actually landing in the user dir is diff/branch-proven, NOT runtime-automated — a coordinator manual acceptance check. No stray output files were written.
8
+
-**Boundary (no overclaim):** output filename is fixed by format (`watermarked.<ext>`), so repeated real saves overwrite — collision-avoiding names remain deferred. Release-grade Desktop save-location correctness, **not** Android v2.10.0 1:1 UI/UX parity; default-template seeding stays deferred. PR #358 Draft.
9
+
-**S4d-217b (this entry):** docs-only closeout — recorded the above in `progress.md`, `task_plan.md`, and the `docs/CONTEXT.md` Desktop-window row.
-**S4d-215 (implementation, accepted; commit `873dbcbd Route Desktop window state to user data dir`, `DesktopWindow.kt` only, +31/-6):** the interactive Compose Desktop window now persists its user state — watermark config, output prefs, and the templates Room DB — under the stable per-user dir `~/.easywatermark` instead of repo-local `build/` dev paths. A new same-file helper `resolveDesktopAppDataDir()` returns `~/.easywatermark` (matching the `CreateDataStore.desktop.kt` convention) and is passed to `DesktopWatermarkFlow.buildRepository(dir = appDataDir)`, `buildUserConfigRepository(dir = appDataDir)`, and `buildTemplateDatabase(appDataDir)`. If `user.home` is null/blank it falls back to a repo-local `build/desktop-app-data` dir with a `System.err` warning (no crash).
0 commit comments