Commit Graph
17 Commits
Author SHA1 Message Date
admin 5b57a4d39a feat: add outfit batch runner 2026-06-18 17:52:05 +08:00
admin 28fcc018bc feat: add outfit generation core 2026-06-18 17:43:35 +08:00
admin fe1dc7778e feat: add ai image service 2026-06-18 17:40:56 +08:00
admin 10238d3da3 feat: add outfit excel service 2026-06-18 17:35:00 +08:00
adminandClaude Opus 4.8 421ae78035 feat: default export dir to <install root>\合并后的图片 when packaged
get_output_dir() now returns <install root>\合并后的图片 (parent of app\) for
frozen builds — next to Launcher.exe, easy to find, not replaced on update.
Falls back to <data_dir>/output if the install root is read-only; dev mode
unchanged. The export panel already uses get_output_dir(), so its default
follows automatically.

- tests/test_file_service.py: +3 (dev, frozen install-root, fallback)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:29:09 +08:00
adminandClaude Opus 4.8 5a1a004daf feat: non-blocking updates — download in app, apply at launch
Startup no longer blocks on a download. New split:
- services/installer.py: download_and_stage() (runs while the app is open →
  staging\app.new, verified) and apply_staged() (launcher swaps it into app\
  at next launch, when the exe isn't locked).
- launcher.py: slimmed to seed + apply_staged + launch; no network at startup.
- main_window: a new version lights a dot on the ⚙ 配置 button instead of a
  blocking banner; the old open-folder banner is removed.
- settings_dialog: "检查并更新" downloads + stages, then "下次启动生效".

Verified end-to-end over a local HTTP server (download→stage→apply); 101 tests
pass (test_installer +11, test_launcher rewritten).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 11:58:06 +08:00
adminandClaude Opus 4.8 2d2c6c839d feat: settings dialog for update config (gear entry)
A low-key "⚙ 配置" button at the right end of the flow-tab row opens a settings
dialog to edit update_source / update_user / update_pass, with a test-connection
button that distinguishes "reachable & up to date" from "cannot connect".

- settings_dialog.py: pure-UI QDialog; password mask + show; test runs off the
  UI thread via load_manifest and reports the result
- update_service: add load_manifest() (raises on failure, unlike check_for_update)
- main_window: gear button, _open_settings persists via save_config and re-runs
  the update check; _update_found connected once to avoid duplicate banners
- tests: +2 for load_manifest

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 11:09:29 +08:00
adminandClaude Opus 4.8 1d8e4fc240 feat: src/launcher.py — Python update launcher (HTTP, app/app.old swap)
Launcher core that reuses services/update_service: seed default config into
~/.cmbot on first run, check the manifest, download the release zip, verify
SHA-256, extract, validate version, swap into app/ (keeping app.old/ for
rollback), then launch app/CMBot.exe. Degrades to the local version on any
failure; checks install-root writability before updating.

- update_service: UpdateInfo gains sha256/size/min_supported; release URL
  resolved to absolute; extract make_auth_header + add download() helper
- tests/test_launcher.py: 11 tests (seed, find-root, swap, sha mismatch,
  no-update); also verified end-to-end against a local HTTP server

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 10:49:45 +08:00
adminandClaude Opus 4.8 3d01bed98c feat: get_data_dir() three-tier fallback (env -> ~/.cmbot -> dev root)
Packaged builds now resolve the data root to ~/.cmbot (%USERPROFILE%\.cmbot)
instead of the program dir, so user config/templates/output stay writable and
per-user regardless of where the program is installed or whether it is launched
via Launcher.exe (docs/10-lan-update.md §5). CMBOT_DATA_DIR still overrides.

- tests/test_file_service.py: 5 tests covering env override, frozen->~/.cmbot,
  dev->project root, blank-env handling

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 10:39:52 +08:00
adminandClaude Opus 4.8 54e42670f7 fix: tolerate UTF-8 BOM in manifest; sync docs to app/app.old model
#1 BOM: PowerShell Set-Content -Encoding UTF8 writes a BOM that made the in-app
json.loads silently fail (banner never showed even with an update available).
- update_service: decode manifest with utf-8-sig (HTTP + local)
- build.ps1: write manifest.json without BOM (UTF8Encoding $false)
- tests: +2 covering BOM manifests (HTTP + local)

#2 docs: docs/10 §16 status synced to the implemented app/app.old/version.txt +
SHA-256 model (stages 2/3 done + e2e verified); tasks 17.18 updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 10:19:03 +08:00
admin 813e569639 feat: support http update checks 2026-06-18 09:38:44 +08:00
adminandClaude Opus 4.8 0392e1c8a2 feat: LAN update check on startup with notify banner (stage 2)
Read manifest.json from the configured update_source and show a dismissable
banner when a newer version is available. Notify-only — no install yet.

- services/update_service.py: version compare + check_for_update (pure, tested)
- config: add update_source key (empty = no check)
- main_window: top banner, background-thread check; open folder via os.startfile
  (QDesktopServices.openUrl mishandles file:// folder URLs — ShellExecute err 2)
- tests: +15 covering version compare and check_for_update branches
- docs 02/05/10 + tasks 17.16

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 17:05:46 +08:00
adminandClaude Opus 4.8 f2b08fecb3 fix: per-item transform in batch export (correct placement across sizes)
QueuePanel reused one pixel TransformState for all non-fine-tuned items,
mis-placing garments/prints of other sizes. Store the ratio-based template
instead and recompute each item from its own garment/print size.

- add core.composer.image_size() and resolve_transform() (pure, tested)
- queue: set_template() replaces set_transform(); per-item resolve + size cache
- template_panel: expose current_template(); main_window pushes it to the queue
- tests: +4 covering fine-tune precedence, per-size recompute, empty inputs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:42:20 +08:00
adminandClaude Opus 4.8 8a34fe93ff feat: thumbnail grid, aspect-aware templates, and UI hierarchy polish
Material list:
- Switch asset list from one-per-row to a wrapping thumbnail grid
  (IconMode cards: thumbnail + corner checkbox + elided name, subfolder
  moved to tooltip).

Templates:
- Template.to_transform_state now contains-fits the print inside the
  target box by the print's native aspect ratio (no stretch); falls back
  to the box when print size is unknown.
- Feed print native size into template_panel for aspect-aware fitting.
- Shrink built-in template boxes to realistic print proportions.

UI hierarchy:
- Promote 打开文件夹 buttons to primary (filled accent).
- Add inline 归零 (reset angle) and a 重置位置/尺寸/角度 button to the
  transform panel; wire it to re-apply the selected template.
- Hide 保存 for built-in templates instead of leaving it greyed.

Docs: record template box/contain behavior (PRD) and the grid layout,
button hierarchy, and reset/save-visibility rules (UI design).
Tests: add 3 aspect-fit cases for to_transform_state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 15:11:56 +08:00
admin c94b600bb6 feat: add low contrast visibility analysis 2026-06-16 11:21:21 +08:00
adminandClaude Sonnet 4.6 d02da738c6 test: add composer and template test suites (43 tests, all passing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 09:38:06 +08:00
QiuSW e91207357b chore: scaffold PySide6 application 2026-06-15 15:53:01 +08:00