From e5c830e945f84e5b559f4ecb77cc868d3bc93e56 Mon Sep 17 00:00:00 2001 From: Sebastian Dine Date: Sun, 19 Jul 2026 12:06:57 +0200 Subject: [PATCH] minor: New Game Digimon Digi-Battle (#17) * digimon digi battle added to supported games * sonarqube update * readme update --------- Co-authored-by: sdine --- .github/workflows/feature-ci.yml | 2 +- .github/workflows/master-ci.yml | 2 +- AGENTS.md | 4 +- README.md | 23 +- app/AGENTS.md | 6 +- app/CMakeLists.txt | 8 +- app/main.cpp | 29 +- core/AGENTS.md | 6 +- core/CMakeLists.txt | 4 + core/include/ccm/domain/DigiBattle99Card.hpp | 38 +++ core/include/ccm/domain/Enums.hpp | 3 +- .../DigiBattle99CardPreviewSource.hpp | 67 +++++ .../digibattle99/DigiBattle99GameModule.hpp | 27 ++ .../digibattle99/DigiBattle99SetSource.hpp | 37 +++ core/include/ccm/services/CardFilter.hpp | 5 + core/include/ccm/services/CardSorter.hpp | 18 ++ core/src/domain/DigiBattle99Card.cpp | 39 +++ core/src/domain/Enums.cpp | 19 +- .../DigiBattle99CardPreviewSource.cpp | 222 +++++++++++++++ .../digibattle99/DigiBattle99GameModule.cpp | 8 + .../digibattle99/DigiBattle99SetSource.cpp | 119 ++++++++ core/src/services/CardFilter.cpp | 15 ++ core/src/services/CardSorter.cpp | 70 +++++ docs/AGENTS.md | 6 +- docs/README.md | 2 +- docs/assets-and-info-apis.md | 46 +++- docs/assets/images/demo-digibattle99.png | Bin 0 -> 270066 bytes docs/caching.md | 2 +- tests/AGENTS.md | 4 +- tests/CMakeLists.txt | 2 + tests/card_filter_tests.cpp | 38 +++ tests/card_sorter_tests.cpp | 64 +++++ ...digibattle99_card_preview_source_tests.cpp | 179 ++++++++++++ tests/digibattle99_set_source_tests.cpp | 112 ++++++++ tests/domain_json_tests.cpp | 62 +++++ tests/game_module_tests.cpp | 12 + tests/local_image_store_tests.cpp | 1 + tests/set_service_tests.cpp | 31 +++ ui_wx/AGENTS.md | 6 +- ui_wx/CMakeLists.txt | 4 + ui_wx/assets/digibattle99_card_back.png | Bin 0 -> 160 bytes ui_wx/include/ccm/ui/AppContext.hpp | 1 + .../include/ccm/ui/BaseSelectedCardPanel.hpp | 14 +- .../ccm/ui/DigiBattle99CardEditDialog.hpp | 81 ++++++ .../ccm/ui/DigiBattle99CardListPanel.hpp | 26 ++ ui_wx/include/ccm/ui/DigiBattle99GameView.hpp | 64 +++++ .../ccm/ui/DigiBattle99SelectedCardPanel.hpp | 25 ++ ui_wx/src/DigiBattle99CardEditDialog.cpp | 255 ++++++++++++++++++ ui_wx/src/DigiBattle99CardListPanel.cpp | 71 +++++ ui_wx/src/DigiBattle99GameView.cpp | 216 +++++++++++++++ ui_wx/src/DigiBattle99SelectedCardPanel.cpp | 84 ++++++ ui_wx/src/MainFrame.cpp | 8 +- ui_wx/src/SettingsDialog.cpp | 32 ++- 53 files changed, 2170 insertions(+), 49 deletions(-) create mode 100644 core/include/ccm/domain/DigiBattle99Card.hpp create mode 100644 core/include/ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp create mode 100644 core/include/ccm/games/digibattle99/DigiBattle99GameModule.hpp create mode 100644 core/include/ccm/games/digibattle99/DigiBattle99SetSource.hpp create mode 100644 core/src/domain/DigiBattle99Card.cpp create mode 100644 core/src/games/digibattle99/DigiBattle99CardPreviewSource.cpp create mode 100644 core/src/games/digibattle99/DigiBattle99GameModule.cpp create mode 100644 core/src/games/digibattle99/DigiBattle99SetSource.cpp create mode 100644 docs/assets/images/demo-digibattle99.png create mode 100644 tests/digibattle99_card_preview_source_tests.cpp create mode 100644 tests/digibattle99_set_source_tests.cpp create mode 100644 ui_wx/assets/digibattle99_card_back.png create mode 100644 ui_wx/include/ccm/ui/DigiBattle99CardEditDialog.hpp create mode 100644 ui_wx/include/ccm/ui/DigiBattle99CardListPanel.hpp create mode 100644 ui_wx/include/ccm/ui/DigiBattle99GameView.hpp create mode 100644 ui_wx/include/ccm/ui/DigiBattle99SelectedCardPanel.hpp create mode 100644 ui_wx/src/DigiBattle99CardEditDialog.cpp create mode 100644 ui_wx/src/DigiBattle99CardListPanel.cpp create mode 100644 ui_wx/src/DigiBattle99GameView.cpp create mode 100644 ui_wx/src/DigiBattle99SelectedCardPanel.cpp diff --git a/.github/workflows/feature-ci.yml b/.github/workflows/feature-ci.yml index 60f7ed0..57d054d 100644 --- a/.github/workflows/feature-ci.yml +++ b/.github/workflows/feature-ci.yml @@ -58,7 +58,7 @@ jobs: --exclude "^tests/" - name: SonarQube Cloud scan - uses: SonarSource/sonarqube-scan-action@v5 + uses: SonarSource/sonarqube-scan-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/master-ci.yml b/.github/workflows/master-ci.yml index 5c70a70..647bc59 100644 --- a/.github/workflows/master-ci.yml +++ b/.github/workflows/master-ci.yml @@ -58,7 +58,7 @@ jobs: --exclude "^tests/" - name: SonarQube Cloud scan - uses: SonarSource/sonarqube-scan-action@v5 + uses: SonarSource/sonarqube-scan-action@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index 377e2b6..9386bc3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ C++ desktop implementation (originally based on a Tauri Rust+TS version) — sin ## Project structure - `core/` — `ccm_core` static library. UI-agnostic domain, ports, services, infra adapters. **Never** depends on wxWidgets. See `core/AGENTS.md`. -- `ui_wx/` — `ccm_ui_wx` static library. The only place that touches wxWidgets. See `ui_wx/AGENTS.md`. Ships `ui_wx/assets/ygo_card_back.png` (Yu-Gi-Oh! offline preview fallback); `app/CMakeLists.txt` copies it to `/assets/` when linking `ccm`. +- `ui_wx/` — `ccm_ui_wx` static library. The only place that touches wxWidgets. See `ui_wx/AGENTS.md`. Ships `ui_wx/assets/ygo_card_back.png` and `ui_wx/assets/digibattle99_card_back.png` (offline preview fallbacks); `app/CMakeLists.txt` copies them to `/assets/` when linking `ccm`. - `app/` — `ccm` executable (composition root). Wires concrete adapters into services. See `app/AGENTS.md`. - `tests/` — `ccm_core_tests` doctest binary. Pure-logic tests against in-memory fakes. See `tests/AGENTS.md`. - `docs/` — long-form developer documentation. Start with `docs/adding-a-new-game.md` for the canonical end-to-end procedure for extending the app with a new TCG. See `docs/AGENTS.md`. @@ -84,7 +84,7 @@ Run from the **workspace root**. - Card preview round-trips are slow (HTTPS handshake + image GET, often two hosts). The three amortizations in place — all game-agnostic — must stay. The full update mechanic (key-driven invalidation, positive↔negative same-key replacement, eviction, manual cache clearing) is documented in `docs/caching.md` → "Updating cached entries"; do **not** add a side-channel `clearCache(...)` API to `CardPreviewService` — keep updates flowing through cache keys so the in-memory and disk tiers stay aligned automatically. - `CardPreviewService` keeps a bounded in-memory LRU (`kCacheCapacity`) of preview bytes keyed by `(game, name, setId, setNo)` plus a by-URL cache for the per-game card-back fallback. Re-selecting a row already viewed in this session is decode-only, no HTTP. Source failures are split by `PreviewLookupError::Kind`: `NotFound` (the upstream answered cleanly that the record has no image) is **negative-cached** so subsequent clicks short-circuit to the card-back placeholder without HTTP, while `Transient` (HTTP/network/parse) is **never** cached so a brief outage can recover on the next selection. Editing a lookup-relevant field changes the cache key and invalidates the negative entry automatically. - `LocalPreviewByteCache` (port `IPreviewByteCache`) extends the LRU with an on-disk byte cache rooted at `/.cache/preview-cache/` — **next to the executable, in the same scope as `config.json`, NOT inside the user-configurable `dataStorage` path** so previews don't follow the user's collection when the data-storage path is reconfigured (the umbrella `.cache/` directory is reserved for any future computed-from-network caches). Both positive previews and `NotFound` verdicts **survive app restarts**. Lookup order is memory → disk → source/HTTP; a disk hit (positive or negative) is promoted into the in-memory tier so the follow-up call stays decode-only. Total `.bin` payload size is capped (default 64 MiB) and oldest-by-mtime entries are evicted when a new write would exceed the cap; tiny `.neg` markers are not counted against the cap. The persistent tier is fire-and-forget: any I/O error is swallowed by the adapter so disk problems can never break the preview path. - - `CprHttpClient` owns a single long-lived `cpr::Session` (and therefore a single libcurl easy handle) with keep-alive enabled, so repeat HTTPS calls to the same host (`api.scryfall.com`, `api.pokemontcg.io`, `db.ygoprodeck.com`, `yugipedia.com`, `ms.yugipedia.com`) reuse the existing TLS connection. Concurrent callers are serialized through a mutex — easy handles are not thread-safe and the preview path is single-flight already. Session default **`Accept: */*`** keeps JSON info APIs and binary image GETs on one client; **`CardPreviewService::fetchAndCache`** rejects empty HTTP bodies so a bogus 200 cannot masquerade as a cached preview. + - `CprHttpClient` owns a single long-lived `cpr::Session` (and therefore a single libcurl easy handle) with keep-alive enabled, so repeat HTTPS calls to the same host (`api.scryfall.com`, `api.pokemontcg.io`, `db.ygoprodeck.com`, `yugipedia.com`, `ms.yugipedia.com`, `digimoncard.io`, `images.digimoncard.io`) reuse the existing TLS connection. Concurrent callers are serialized through a mutex — easy handles are not thread-safe and the preview path is single-flight already. Session default **`Accept: */*`** keeps JSON info APIs and binary image GETs on one client; **`CardPreviewService::fetchAndCache`** rejects empty HTTP bodies so a bogus 200 cannot masquerade as a cached preview. ## Windows UI theming guardrails diff --git a/README.md b/README.md index 992790d..8344da1 100644 --- a/README.md +++ b/README.md @@ -9,21 +9,38 @@ Currently, the application supports the following TCGs: - Magic the Gathering - Pokemon TCG - Yu-Gi-Oh! +- Digimon (Digi-Battle) ## Screenshots -### Magic The Gathering +
+Magic The Gathering ![CCM3 Demo - Magic: The Gathering](docs/assets/images/demo-mtg.png) -### Pokemon TCG +
+ +
+Pokemon TCG ![CCM3 Demo - Pokemon](docs/assets/images/demo-pkm.png) -### Yu-Gi-Oh! +
+ +
+Yu-Gi-Oh! ![CCM3 Demo - YuGiOh](docs/assets/images/demo-ygo.png) +
+ +
+Digimon (Digi-Battle) + +![CCM3 Demo - Digimon Digi-Battle](docs/assets/images/demo-digibattle99.png) + +
+ ## Migrating From CCM1 And CCM2 diff --git a/app/AGENTS.md b/app/AGENTS.md index 3b3a523..4062cb8 100644 --- a/app/AGENTS.md +++ b/app/AGENTS.md @@ -5,11 +5,11 @@ The `ccm` executable — composition root only. The single place where concrete ## File pointers - `main.cpp` — the entire app. Defines `CcmApp : public wxApp`, builds the dependency graph in `OnInit()`, then hands an `AppContext` to `MainFrame`. -- `CMakeLists.txt` — declares the `ccm` target. Sets `WIN32_EXECUTABLE TRUE` on Windows so no console window appears. Links `ccm_core`, `ccm_ui_wx`, `ccm_warnings`. **`POST_BUILD`**: creates `$/assets/` and copies `ui_wx/assets/ygo_card_back.png` there so Yu-Gi-Oh! preview fallbacks work offline (see `BaseSelectedCardPanel` / `docs/assets-and-info-apis.md`). +- `CMakeLists.txt` — declares the `ccm` target. Sets `WIN32_EXECUTABLE TRUE` on Windows so no console window appears. Links `ccm_core`, `ccm_ui_wx`, `ccm_warnings`. **`POST_BUILD`**: creates `$/assets/` and copies `ui_wx/assets/ygo_card_back.png` and `ui_wx/assets/digibattle99_card_back.png` there so Yu-Gi-Oh! / Digi-Battle preview fallbacks work offline (see `BaseSelectedCardPanel` / `docs/assets-and-info-apis.md`). ## Conventions -1. **Composition root is the only place** that names concrete adapters: `StdFileSystem`, `CprHttpClient`, `JsonCollectionRepository`, `JsonCollectionRepository`, `JsonCollectionRepository`, `JsonSetRepository`, `LocalImageStore`, `LocalPreviewByteCache`, `MagicGameModule`, `PokemonGameModule`, `YuGiOhGameModule`, `MagicGameView`, `PokemonGameView`, `YuGiOhGameView`, etc. If a concrete adapter type appears anywhere else in the codebase, move the wiring here. +1. **Composition root is the only place** that names concrete adapters: `StdFileSystem`, `CprHttpClient`, `JsonCollectionRepository`, `JsonCollectionRepository`, `JsonCollectionRepository`, `JsonCollectionRepository`, `JsonSetRepository`, `LocalImageStore`, `LocalPreviewByteCache`, `MagicGameModule`, `PokemonGameModule`, `YuGiOhGameModule`, `DigiBattle99GameModule`, `MagicGameView`, `PokemonGameView`, `YuGiOhGameView`, `DigiBattle99GameView`, etc. If a concrete adapter type appears anywhere else in the codebase, move the wiring here. 2. **Member declaration order in `CcmApp` matters** — destruction is reverse, so a member that depends on another (e.g. `magicCollSvc_` depends on `magicRepo_` and `imgStore_`; `previewSvc_` depends on `http_` and is consumed by `ctx_`; `magicView_` depends on the typed `magicCollSvc_` and the shared services) must be declared **after** its deps. Do not reorder casually. 3. **Use `std::unique_ptr` for everything owned** by `CcmApp`. The `AppContext` then holds plain references into those owned objects, plus a vector of `IGameView*` raw pointers (the `unique_ptr<>`s for the views are the actual owners; the vector just describes the active set). 4. **Game-to-directory mapping** lives in `dirNameForGame(Game)` (anonymous namespace). When adding a new game, extend this function — it is wired into all three repositories (`JsonCollectionRepository`, `JsonSetRepository`, `LocalImageStore`). @@ -21,7 +21,7 @@ The `ccm` executable — composition root only. The single place where concrete ## Required follow-ups -- The **`POST_BUILD` copy of `ygo_card_back.png`** must stay in sync with `ui_wx/assets/`; if you relocate install layout or add more bundled assets, mirror the pattern (`make_directory` + `copy_if_different`) and document under `docs/assets-and-info-apis.md` / `ui_wx/AGENTS.md`. +- The **`POST_BUILD` copy of `ygo_card_back.png` / `digibattle99_card_back.png`** must stay in sync with `ui_wx/assets/`; if you relocate install layout or add more bundled assets, mirror the pattern (`make_directory` + `copy_if_different`) and document under `docs/assets-and-info-apis.md` / `ui_wx/AGENTS.md`. - After adding a new game module you **must**: (1) add a `unique_ptr<GameModule>` member in declaration-order-correct position, (2) construct it in `OnInit()`, (3) call `setSvc_->registerModule(Mod_.get())`, (4) call `previewSvc_->registerModule(*Mod_)` (no-op when the module has no preview source), (5) extend `dirNameForGame`, (6) add a typed `JsonCollectionRepository<Card>` + `CollectionService<Card>` if the game has a custom card type, (7) construct a `GameView` and append its raw pointer to the `AppContext::gameViews` vector, (8) make sure the view's `unique_ptr<>` member sits **after** all its deps (typed services + `IGameModule`). - After adding a new core service you **must** add a `unique_ptr<...>` member, construct it in `OnInit()` after its deps, and add a reference field to `AppContext`. - After adding a new dependency edge you **must** verify destruction order is still correct: deps **before** dependents in the member list. diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5e7382d..1f2e059 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -19,9 +19,13 @@ target_link_libraries(ccm ccm_warnings ) -# Yu-Gi-Oh! preview fallback image (used when network card-back URLs fail). +# Yu-Gi-Oh! / Digi-Battle preview fallback images (used when network card-back +# URLs fail or no public URL exists). add_custom_command(TARGET ccm POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "$/assets" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/ui_wx/assets/ygo_card_back.png" - "$/assets/ygo_card_back.png") + "$/assets/ygo_card_back.png" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_SOURCE_DIR}/ui_wx/assets/digibattle99_card_back.png" + "$/assets/digibattle99_card_back.png") diff --git a/app/main.cpp b/app/main.cpp index 2ba87b1..03d1815 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -2,9 +2,11 @@ // it to the wxWidgets UI layer. This is the only place where concrete adapter // types are mentioned - everything downstream depends on interfaces. +#include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" #include "ccm/domain/YuGiOhCard.hpp" +#include "ccm/games/digibattle99/DigiBattle99GameModule.hpp" #include "ccm/games/magic/MagicGameModule.hpp" #include "ccm/games/pokemon/PokemonGameModule.hpp" #include "ccm/games/yugioh/YuGiOhGameModule.hpp" @@ -20,6 +22,7 @@ #include "ccm/services/ImageService.hpp" #include "ccm/services/SetService.hpp" #include "ccm/ui/AppContext.hpp" +#include "ccm/ui/DigiBattle99GameView.hpp" #include "ccm/ui/MagicGameView.hpp" #include "ccm/ui/MainFrame.hpp" #include "ccm/ui/PokemonGameView.hpp" @@ -42,9 +45,10 @@ namespace { // need for the repositories to know about concrete game module classes. std::string dirNameForGame(ccm::Game g) { switch (g) { - case ccm::Game::Magic: return "magic"; - case ccm::Game::Pokemon: return "pokemon"; - case ccm::Game::YuGiOh: return "yugioh"; + case ccm::Game::Magic: return "magic"; + case ccm::Game::Pokemon: return "pokemon"; + case ccm::Game::YuGiOh: return "yugioh"; + case ccm::Game::DigiBattle99: return "digibattle99"; } return "magic"; } @@ -80,6 +84,7 @@ public: magicMod_ = std::make_unique(*http_); pokeMod_ = std::make_unique(*http_); ygoMod_ = std::make_unique(*http_); + digiBattle99Mod_ = std::make_unique(*http_); magicRepo_ = std::make_unique>( *fs_, *config_, &dirNameForGame); @@ -87,6 +92,9 @@ public: *fs_, *config_, &dirNameForGame); ygoRepo_ = std::make_unique>( *fs_, *config_, &dirNameForGame); + digiBattle99Repo_ = + std::make_unique>( + *fs_, *config_, &dirNameForGame); setRepo_ = std::make_unique(*fs_, *config_, &dirNameForGame); imgStore_ = std::make_unique(*fs_, *config_, &dirNameForGame); @@ -97,10 +105,14 @@ public: *pokeRepo_, *imgStore_); ygoCollSvc_ = std::make_unique>( *ygoRepo_, *imgStore_); + digiBattle99CollSvc_ = + std::make_unique>( + *digiBattle99Repo_, *imgStore_); setSvc_ = std::make_unique(*setRepo_); setSvc_->registerModule(magicMod_.get()); setSvc_->registerModule(pokeMod_.get()); setSvc_->registerModule(ygoMod_.get()); + setSvc_->registerModule(digiBattle99Mod_.get()); // Disk-backed preview cache lives next to the executable, in the same // location scope as config.json - NOT inside the user's data-storage @@ -120,6 +132,7 @@ public: previewSvc_->registerModule(*magicMod_); previewSvc_->registerModule(*pokeMod_); previewSvc_->registerModule(*ygoMod_); + previewSvc_->registerModule(*digiBattle99Mod_); // Per-game UI bundles. Order here is the order shown in the Game menu. magicView_ = std::make_unique( @@ -128,6 +141,9 @@ public: *config_, *pokeCollSvc_, *setSvc_, *imgSvc_, *previewSvc_, *pokeMod_); ygoView_ = std::make_unique( *config_, *ygoCollSvc_, *setSvc_, *imgSvc_, *previewSvc_, *ygoMod_); + digiBattle99View_ = std::make_unique( + *config_, *digiBattle99CollSvc_, *setSvc_, *imgSvc_, *previewSvc_, + *digiBattle99Mod_); ctx_ = std::make_unique(ccm::ui::AppContext{ *config_, @@ -137,7 +153,8 @@ public: *magicMod_, *pokeMod_, *ygoMod_, - { magicView_.get(), pokeView_.get(), ygoView_.get() }, + *digiBattle99Mod_, + { magicView_.get(), pokeView_.get(), ygoView_.get(), digiBattle99View_.get() }, }); auto* frame = new ccm::ui::MainFrame(*ctx_); @@ -158,21 +175,25 @@ private: std::unique_ptr magicMod_; std::unique_ptr pokeMod_; std::unique_ptr ygoMod_; + std::unique_ptr digiBattle99Mod_; std::unique_ptr> magicRepo_; std::unique_ptr> pokeRepo_; std::unique_ptr> ygoRepo_; + std::unique_ptr> digiBattle99Repo_; std::unique_ptr setRepo_; std::unique_ptr imgStore_; std::unique_ptr imgSvc_; std::unique_ptr> magicCollSvc_; std::unique_ptr> pokeCollSvc_; std::unique_ptr> ygoCollSvc_; + std::unique_ptr> digiBattle99CollSvc_; std::unique_ptr setSvc_; std::unique_ptr previewCache_; std::unique_ptr previewSvc_; std::unique_ptr magicView_; std::unique_ptr pokeView_; std::unique_ptr ygoView_; + std::unique_ptr digiBattle99View_; std::unique_ptr ctx_; }; diff --git a/core/AGENTS.md b/core/AGENTS.md index a210e3a..2e74c00 100644 --- a/core/AGENTS.md +++ b/core/AGENTS.md @@ -4,11 +4,11 @@ ## Layer pointers -- `include/ccm/domain/` — POD value types: `Enums`, `Set`, `MagicCard`, `PokemonCard`, `YuGiOhCard`, `Configuration`. Each has `to_json` / `from_json` defined in the matching `src/domain/*.cpp`. +- `include/ccm/domain/` — POD value types: `Enums`, `Set`, `MagicCard`, `PokemonCard`, `YuGiOhCard`, `DigiBattle99Card`, `Configuration`. Each has `to_json` / `from_json` defined in the matching `src/domain/*.cpp`. - `include/ccm/ports/` — interfaces (`IHttpClient`, `IFileSystem`, `ICollectionRepository`, `ISetRepository`, `IImageStore`, `ICardPreviewSource`, `IPreviewByteCache`). All seams the services depend on. Add new ports here when adding new external concerns. - `include/ccm/services/` — high-level operations: `ConfigService`, `CollectionService` (header-only template), `SetService`, `ImageService`, `CardPreviewService`, `CardSorter` (free functions; per-column sort comparators that mirror established table sorting behavior — UI-agnostic so they can be unit-tested directly), `CardFilter` (free functions; case-insensitive substring row matcher restricted to each game's `tableFields` valueKey list). They depend only on ports. - `include/ccm/infra/` — concrete adapters: `CprHttpClient`, `StdFileSystem`, `JsonCollectionRepository` (header-only template), `JsonSetRepository`, `LocalImageStore`, `LocalPreviewByteCache`. -- `include/ccm/games/` — `IGameModule` + per-game modules. `IGameModule` consolidates the per-game seams: every module owns an `ISetSource` (required) and may own an `ICardPreviewSource` (optional, default `nullptr`). `magic/`, `pokemon/`, and `yugioh/` are the reference implementations — all three expose a fully working set source + card preview source. +- `include/ccm/games/` — `IGameModule` + per-game modules. `IGameModule` consolidates the per-game seams: every module owns an `ISetSource` (required) and may own an `ICardPreviewSource` (optional, default `nullptr`). `magic/`, `pokemon/`, `yugioh/`, and `digibattle99/` are the reference implementations — all four expose a fully working set source + card preview source. - `include/ccm/util/` — `Result.hpp` (the sum type), `FsNames.hpp` (filename munging ported from `util/fs.rs`), `YuGiOhPrintingSlot.hpp` / `YuGiOhSetLookup.hpp` (Yu-Gi-Oh! print-slot helpers and cached-set **set code** lookup for the edit dialog; both header-only, unit-tested). - `src/` mirrors `include/ccm/` for non-template implementations. @@ -27,7 +27,7 @@ 8. **HTTP query strings must be percent-encoded** before they reach `IHttpClient::get`. `cpr::Url` does **not** encode the URL string we hand it. See `MagicCardPreviewSource::buildSearchUrl` for the canonical pattern (RFC 3986 unreserved-set encoder). `IHttpClient::get` accepts arbitrary bytes back — `Result` is a binary buffer, not text, so callers can use it for image payloads directly. 9. **Yu-Gi-Oh! preview uses Yugipedia, not YGOPRODeck.** `YuGiOhCardPreviewSource::fetchImageUrl` queries Yugipedia's MediaWiki API with a batched list of deterministic file names (`----.`) so per-printing reprints with shared passcodes (LOB Blue-Eyes vs SDK Blue-Eyes, …) resolve to genuinely different scans. Region candidates are **always English** (`EN`/`NA`/`EU`/`AU`) regardless of `card.language`; localized scans are not queried. YGOPRODeck remains as a last-resort fallback (see `parseFallbackImageUrl`) for cards Yugipedia hasn't scanned yet, and as the source for `detectFirstPrint` / `detectPrintVariants` (`parsePrintVariants` enumerates distinct printings for the edit dialog). **Do not** restore a YGOPRODeck-only image path: that endpoint's `card_images` array is keyed by art-treatment passcode, not by physical printing, and adding `cardset=` only reorders the same passcode list (alt-art often gets promoted) without ever surfacing the per-printing scan. The YGO source therefore needs the printed edition flag to be plumbed through; `YuGiOhSelectedCardPanel::previewKey()` packs it into the third tuple slot as `||||<1E|UE>` so the candidate list can prioritize the correct edition without changing the generic `ICardPreviewSource` interface. 10. **Preview byte cache (`CardPreviewService`) is by `(game, name, setId, setNo)` across two tiers, with classified failure caching and a single update mechanic.** Successful `fetchPreviewBytes` results and successful `fetchImageBytesByUrl` results are stored first in a bounded in-memory LRU (`kCacheCapacity` entries, mutex-protected — the panel calls into the service from a worker thread) and then in an optional persistent byte cache (`IPreviewByteCache`, normally `LocalPreviewByteCache` rooted at `/.cache/preview-cache/` — next to the executable, **not** under `dataStorage`, so previews don't follow the user's collection when the data-storage path is reconfigured). **`fetchAndCache` rejects empty response bodies** (returns error, no tier write) so a degenerate HTTP 200 cannot fill the LRU with unusable entries. Lookup order is **memory → disk → source/HTTP**, and a disk hit (positive *or* negative) is promoted into the in-memory tier on its way to the caller so the next selection of the same row stays decode-only. **Failures are split by `PreviewLookupError::Kind`**: `NotFound` is negative-cached in both tiers (memory `CacheEntry::negative=true`, disk `.neg` marker) so the user gets an instant card-back on every subsequent click for cards whose printing genuinely has no upstream image; `Transient` (HTTP/network/parse failures) is **never** cached so a brief outage cannot permanently disable previews. Per-game `ICardPreviewSource::fetchImageUrl` implementations must classify their errors honestly — `NotFound` only when the upstream answered cleanly with no match / no image variants; anything that could be the network or a schema deviation is `Transient`. **The cache update mechanic is entirely key-driven and has no side-channel API:** (a) the user editing any lookup-relevant field of a card record changes the cache key, so the next selection misses both tiers and re-runs the source — this is how a stale negative entry gets dislodged after the user fixes the record, with no manual invalidation call needed; (b) a same-key resolution that flips between positive and negative outcomes overwrites the existing entry in both tiers (`store` removes any `.neg` for that hash; `storeNegative` removes any `.bin`) so `.bin` and `.neg` for the same hash are never co-resident; (c) eviction handles passive aging (LRU on the in-memory tier; oldest-by-mtime `.bin` files on the disk tier; `.neg` markers don't count against the size cap and are not actively evicted). **Do not add a `clearCache(...)` / `invalidate(...)` method** to `CardPreviewService`: the cache invariants depend on memory and disk staying aligned through the same write paths, and any side-channel API would just be a new way for future code to forget the disk tier. If you add a new lookup disambiguator (for example a future `editionTag` slot), pack it into one of the existing key fields (see `YuGiOhSelectedCardPanel::previewKey()`'s `||`-separated trailing fields) so editing the field continues to invalidate cached entries automatically. The persistent tier is **fire-and-forget**: the adapter swallows I/O errors so a flaky or full disk degrades the experience to a fresh-install warm-up, never to a broken preview path. -11. **`CprHttpClient` keeps one persistent `cpr::Session` for the app's lifetime.** All callers (set sources, preview sources, fallback URL fetch, auto-detect) share the same libcurl easy handle so connections to repeat hosts (`api.scryfall.com`, `api.pokemontcg.io`, `db.ygoprodeck.com`, `yugipedia.com`, `ms.yugipedia.com`) are reused with TLS keep-alive. Default request headers use **`Accept: */*`** so JSON endpoints and binary image downloads share one session without pinning every GET to `application/json`. The session is not thread-safe — every `get(...)` is serialized through an internal mutex. **Do not** construct a new `cpr::Session` (or `cpr::Get(...)`) per call: that throws away the connection cache and re-pays the TLS handshake every time. If you need richer behavior on the port (POST, headers per call, …) extend `IHttpClient` and the adapter while keeping the single-session ownership intact. +11. **`CprHttpClient` keeps one persistent `cpr::Session` for the app's lifetime.** All callers (set sources, preview sources, fallback URL fetch, auto-detect) share the same libcurl easy handle so connections to repeat hosts (`api.scryfall.com`, `api.pokemontcg.io`, `db.ygoprodeck.com`, `yugipedia.com`, `ms.yugipedia.com`, `digimoncard.io`, `images.digimoncard.io`) are reused with TLS keep-alive. Default request headers use **`Accept: */*`** so JSON endpoints and binary image downloads share one session without pinning every GET to `application/json`. The session is not thread-safe — every `get(...)` is serialized through an internal mutex. **Do not** construct a new `cpr::Session` (or `cpr::Get(...)`) per call: that throws away the connection cache and re-pays the TLS handshake every time. If you need richer behavior on the port (POST, headers per call, …) extend `IHttpClient` and the adapter while keeping the single-session ownership intact. ## Adding a new game diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 984bdaa..43dce74 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(ccm_core STATIC src/domain/MagicCard.cpp src/domain/PokemonCard.cpp src/domain/YuGiOhCard.cpp + src/domain/DigiBattle99Card.cpp src/domain/Configuration.cpp src/services/ConfigService.cpp @@ -31,6 +32,9 @@ add_library(ccm_core STATIC src/games/yugioh/YuGiOhSetSource.cpp src/games/yugioh/YuGiOhCardPreviewSource.cpp src/games/yugioh/YuGiOhGameModule.cpp + src/games/digibattle99/DigiBattle99SetSource.cpp + src/games/digibattle99/DigiBattle99CardPreviewSource.cpp + src/games/digibattle99/DigiBattle99GameModule.cpp src/util/FsNames.cpp ) diff --git a/core/include/ccm/domain/DigiBattle99Card.hpp b/core/include/ccm/domain/DigiBattle99Card.hpp new file mode 100644 index 0000000..e68f5ed --- /dev/null +++ b/core/include/ccm/domain/DigiBattle99Card.hpp @@ -0,0 +1,38 @@ +#pragma once + +// DigiBattle99Card - Digimon Digi-Battle (1999 English) card model. +// Pokémon-shaped field set (setNo / holo / firstEdition / signed / altered). + +#include "ccm/domain/Enums.hpp" +#include "ccm/domain/Set.hpp" + +#include + +#include +#include +#include + +namespace ccm { + +struct DigiBattle99Card { + std::uint32_t id{0}; + std::uint8_t amount{1}; + std::string name; + Set set; + std::string setNo; + std::string note; + std::vector images; + Language language{Language::English}; + Condition condition{Condition::NearMint}; + bool firstEdition{false}; + bool holo{false}; + bool signed_{false}; + bool altered{false}; + + friend bool operator==(const DigiBattle99Card&, const DigiBattle99Card&) = default; +}; + +void to_json(nlohmann::json& j, const DigiBattle99Card& c); +void from_json(const nlohmann::json& j, DigiBattle99Card& c); + +} // namespace ccm diff --git a/core/include/ccm/domain/Enums.hpp b/core/include/ccm/domain/Enums.hpp index 22c6cbd..dd3854f 100644 --- a/core/include/ccm/domain/Enums.hpp +++ b/core/include/ccm/domain/Enums.hpp @@ -19,6 +19,7 @@ enum class Game { Magic, Pokemon, YuGiOh, + DigiBattle99, }; enum class Language { @@ -57,7 +58,7 @@ std::optional languageFromString(std::string_view s) noexcept; std::optional conditionFromString(std::string_view s) noexcept; std::optional themeFromString(std::string_view s) noexcept; -const std::array& allGames() noexcept; +const std::array& allGames() noexcept; const std::array& allLanguages() noexcept; const std::array& allConditions() noexcept; const std::array& allThemes() noexcept; diff --git a/core/include/ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp b/core/include/ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp new file mode 100644 index 0000000..3f6c57b --- /dev/null +++ b/core/include/ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp @@ -0,0 +1,67 @@ +#pragma once + +// DigiBattle99CardPreviewSource: digimoncard.io search + CDN card images for +// Digimon Digi-Battle (1999 English). +// +// Preview key middle slot is Set.name (pack display name) so search.php?pack= +// works without a reverse slug map. When setNo is present, the CDN URL is +// built directly — no search round-trip. + +#include "ccm/ports/ICardPreviewSource.hpp" +#include "ccm/ports/IHttpClient.hpp" + +#include +#include +#include + +namespace ccm { + +class DigiBattle99CardPreviewSource final : public ICardPreviewSource { +public: + static constexpr const char* kSeries = "Digimon Digi-Battle Card Game"; + static constexpr const char* kImageBase = + "https://images.digimoncard.io/images/cards/"; + + explicit DigiBattle99CardPreviewSource(IHttpClient& http); + + [[nodiscard]] bool supportsAutoDetectPrint() const noexcept override { return true; } + + Result + fetchImageUrl(std::string_view name, + std::string_view setName, + std::string_view setNo) override; + Result detectFirstPrint(std::string_view name, + std::string_view setName) override; + Result> detectPrintVariants(std::string_view name, + std::string_view setName) override; + + // Uppercase the alphabetic prefix of a Digi-Battle card number (bo-88 -> BO-88). + // Does not invent zero-padding — CDN keys match API ids literally. + static std::string normalizeCardNumber(std::string_view setNo); + + // CDN preview URL for a normalized card id (.jpg — wxImage registers + // JPEG/PNG only; digimoncard.io also serves .webp but we cannot decode it). + static std::string buildImageUrl(std::string_view setNo); + + // digimoncard.io search URL: n= / pack= / series= / optional card=. + // setName is the pack display name (Set.name), not the slug id. + static std::string buildSearchUrl(std::string_view name, + std::string_view setName, + std::string_view setNo); + + // Parse a digimoncard.io search.php body into a CDN image URL for the + // first exact name match (optional pack filter applied by the request). + static Result + parseImageUrlFromSearch(const std::string& body, + std::string_view wantedCardName); + + static Result> + parsePrintVariants(const std::string& body, + std::string_view setName, + std::string_view wantedCardName); + +private: + IHttpClient& http_; +}; + +} // namespace ccm diff --git a/core/include/ccm/games/digibattle99/DigiBattle99GameModule.hpp b/core/include/ccm/games/digibattle99/DigiBattle99GameModule.hpp new file mode 100644 index 0000000..c8346bd --- /dev/null +++ b/core/include/ccm/games/digibattle99/DigiBattle99GameModule.hpp @@ -0,0 +1,27 @@ +#pragma once + +// DigiBattle99GameModule: Digimon Digi-Battle (1999 English) via digimoncard.io. + +#include "ccm/games/IGameModule.hpp" +#include "ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp" +#include "ccm/games/digibattle99/DigiBattle99SetSource.hpp" + +namespace ccm { + +class DigiBattle99GameModule final : public IGameModule { +public: + explicit DigiBattle99GameModule(IHttpClient& http); + + [[nodiscard]] Game id() const noexcept override { return Game::DigiBattle99; } + [[nodiscard]] std::string dirName() const override { return "digibattle99"; } + [[nodiscard]] std::string displayName() const override { return "Digimon (Digi-Battle)"; } + + ISetSource& setSource() override { return setSource_; } + ICardPreviewSource* cardPreviewSource() noexcept override { return &previewSource_; } + +private: + DigiBattle99SetSource setSource_; + DigiBattle99CardPreviewSource previewSource_; +}; + +} // namespace ccm diff --git a/core/include/ccm/games/digibattle99/DigiBattle99SetSource.hpp b/core/include/ccm/games/digibattle99/DigiBattle99SetSource.hpp new file mode 100644 index 0000000..831864d --- /dev/null +++ b/core/include/ccm/games/digibattle99/DigiBattle99SetSource.hpp @@ -0,0 +1,37 @@ +#pragma once + +// DigiBattle99SetSource: ISetSource for Digimon Digi-Battle (1999 English). +// digimoncard.io has no dedicated sets endpoint; we derive unique pack names +// from a bulk search.php call scoped to series=Digimon Digi-Battle Card Game. + +#include "ccm/games/IGameModule.hpp" +#include "ccm/ports/IHttpClient.hpp" + +#include +#include + +namespace ccm { + +class DigiBattle99SetSource final : public ISetSource { +public: + static constexpr const char* kEndpoint = + "https://digimoncard.io/api-public/search.php?" + "series=Digimon%20Digi-Battle%20Card%20Game&limit=1000&sort=name&sortdirection=asc"; + + static constexpr const char* kSeries = "Digimon Digi-Battle Card Game"; + + explicit DigiBattle99SetSource(IHttpClient& http); + + Result> fetchAll() override; + + // Pure parser exposed for unit testing without a network round-trip. + static Result> parseResponse(const std::string& body); + + // Stable Set.id from a pack display name (ASCII lower, non-alnum -> '-'). + static std::string slugifyPackName(std::string_view packName); + +private: + IHttpClient& http_; +}; + +} // namespace ccm diff --git a/core/include/ccm/services/CardFilter.hpp b/core/include/ccm/services/CardFilter.hpp index 4752218..25013f6 100644 --- a/core/include/ccm/services/CardFilter.hpp +++ b/core/include/ccm/services/CardFilter.hpp @@ -19,6 +19,7 @@ // * An empty filter matches every row, exactly as in JS where every string // `.includes("")` returns true. +#include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" #include "ccm/domain/YuGiOhCard.hpp" @@ -41,4 +42,8 @@ namespace ccm { [[nodiscard]] bool matchesYuGiOhFilter(const YuGiOhCard& card, std::string_view filter); +// Digi-Battle mirrors Pokemon searchable columns (includes setNo). +[[nodiscard]] bool matchesDigiBattle99Filter(const DigiBattle99Card& card, + std::string_view filter); + } // namespace ccm diff --git a/core/include/ccm/services/CardSorter.hpp b/core/include/ccm/services/CardSorter.hpp index 0fe9dbb..b54f16c 100644 --- a/core/include/ccm/services/CardSorter.hpp +++ b/core/include/ccm/services/CardSorter.hpp @@ -16,6 +16,7 @@ // UI relies on it so successive clicks on different columns compose predictably // (e.g. sort by name, then by set => grouped by set, name-sorted within each). +#include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" #include "ccm/domain/YuGiOhCard.hpp" @@ -66,6 +67,20 @@ enum class YuGiOhSortColumn { Note, }; +// Digi-Battle mirrors Pokemon columns (setNo is filter-only, not a sort column). +enum class DigiBattle99SortColumn { + Name, + SetReleaseDate, + Language, + Condition, + Amount, + Holo, + FirstEdition, + Signed, + Altered, + Note, +}; + // Stable in-place sort. `ascending=false` runs the same comparator with // inverted sign, matching `byField(field, asc)` semantics. void sortMagicCards(std::vector& cards, MagicSortColumn column, @@ -74,5 +89,8 @@ void sortPokemonCards(std::vector& cards, PokemonSortColumn column, bool ascending); void sortYuGiOhCards(std::vector& cards, YuGiOhSortColumn column, bool ascending); +void sortDigiBattle99Cards(std::vector& cards, + DigiBattle99SortColumn column, + bool ascending); } // namespace ccm diff --git a/core/src/domain/DigiBattle99Card.cpp b/core/src/domain/DigiBattle99Card.cpp new file mode 100644 index 0000000..0132bbc --- /dev/null +++ b/core/src/domain/DigiBattle99Card.cpp @@ -0,0 +1,39 @@ +#include "ccm/domain/DigiBattle99Card.hpp" + +namespace ccm { + +void to_json(nlohmann::json& j, const DigiBattle99Card& c) { + j = nlohmann::json{ + {"id", c.id}, + {"amount", c.amount}, + {"name", c.name}, + {"set", c.set}, + {"setNo", c.setNo}, + {"note", c.note}, + {"images", c.images}, + {"language", c.language}, + {"condition", c.condition}, + {"firstEdition", c.firstEdition}, + {"holo", c.holo}, + {"signed", c.signed_}, + {"altered", c.altered}, + }; +} + +void from_json(const nlohmann::json& j, DigiBattle99Card& c) { + j.at("id").get_to(c.id); + j.at("amount").get_to(c.amount); + j.at("name").get_to(c.name); + j.at("set").get_to(c.set); + j.at("setNo").get_to(c.setNo); + j.at("note").get_to(c.note); + j.at("images").get_to(c.images); + j.at("language").get_to(c.language); + j.at("condition").get_to(c.condition); + j.at("firstEdition").get_to(c.firstEdition); + j.at("holo").get_to(c.holo); + j.at("signed").get_to(c.signed_); + j.at("altered").get_to(c.altered); +} + +} // namespace ccm diff --git a/core/src/domain/Enums.cpp b/core/src/domain/Enums.cpp index 55bbab8..bf2406e 100644 --- a/core/src/domain/Enums.cpp +++ b/core/src/domain/Enums.cpp @@ -13,9 +13,10 @@ namespace ccm { std::string_view to_string(Game g) noexcept { switch (g) { - case Game::Magic: return "Magic"; - case Game::Pokemon: return "Pokemon"; - case Game::YuGiOh: return "YuGiOh"; + case Game::Magic: return "Magic"; + case Game::Pokemon: return "Pokemon"; + case Game::YuGiOh: return "YuGiOh"; + case Game::DigiBattle99: return "DigiBattle99"; } CCM_UNREACHABLE(); } @@ -56,9 +57,10 @@ std::string_view to_string(Theme t) noexcept { } std::optional gameFromString(std::string_view s) noexcept { - if (s == "Magic") return Game::Magic; - if (s == "Pokemon") return Game::Pokemon; - if (s == "YuGiOh") return Game::YuGiOh; + if (s == "Magic") return Game::Magic; + if (s == "Pokemon") return Game::Pokemon; + if (s == "YuGiOh") return Game::YuGiOh; + if (s == "DigiBattle99") return Game::DigiBattle99; return std::nullopt; } @@ -91,8 +93,9 @@ std::optional themeFromString(std::string_view s) noexcept { return std::nullopt; } -const std::array& allGames() noexcept { - static constexpr std::array v{Game::Magic, Game::Pokemon, Game::YuGiOh}; +const std::array& allGames() noexcept { + static constexpr std::array v{ + Game::Magic, Game::Pokemon, Game::YuGiOh, Game::DigiBattle99}; return v; } diff --git a/core/src/games/digibattle99/DigiBattle99CardPreviewSource.cpp b/core/src/games/digibattle99/DigiBattle99CardPreviewSource.cpp new file mode 100644 index 0000000..2f2ae37 --- /dev/null +++ b/core/src/games/digibattle99/DigiBattle99CardPreviewSource.cpp @@ -0,0 +1,222 @@ +#include "ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp" + +#include "ccm/util/Rfc3986.hpp" + +#include + +#include +#include +#include +#include + +namespace ccm { + +namespace { + +std::string trim(std::string s) { + while (!s.empty() && std::isspace(static_cast(s.front()))) s.erase(s.begin()); + while (!s.empty() && std::isspace(static_cast(s.back()))) s.pop_back(); + return s; +} + +std::string toLower(std::string s) { + for (char& ch : s) { + ch = static_cast(std::tolower(static_cast(ch))); + } + return s; +} + +bool cardInPack(const nlohmann::json& card, std::string_view packName) { + if (packName.empty()) return true; + if (!card.contains("set_name") || !card.at("set_name").is_array()) return false; + for (const auto& pack : card.at("set_name")) { + if (pack.is_string() && pack.get() == packName) return true; + } + return false; +} + +} // namespace + +DigiBattle99CardPreviewSource::DigiBattle99CardPreviewSource(IHttpClient& http) + : http_(http) {} + +std::string DigiBattle99CardPreviewSource::normalizeCardNumber(std::string_view setNo) { + std::string s = trim(std::string(setNo)); + if (s.empty()) return s; + // Uppercase leading alphabetic prefix (ST / BO / MO / Fx-style). + std::size_t i = 0; + while (i < s.size() && std::isalpha(static_cast(s[i]))) { + s[i] = static_cast(std::toupper(static_cast(s[i]))); + ++i; + } + return s; +} + +std::string DigiBattle99CardPreviewSource::buildImageUrl(std::string_view setNo) { + const std::string id = normalizeCardNumber(setNo); + return std::string(kImageBase) + id + ".jpg"; +} + +std::string DigiBattle99CardPreviewSource::buildSearchUrl(std::string_view name, + std::string_view setName, + std::string_view setNo) { + std::string url = "https://digimoncard.io/api-public/search.php?series="; + url += rfc3986PercentEncode(kSeries); + if (!name.empty()) { + url += "&n="; + url += rfc3986PercentEncode(name); + } + if (!setName.empty()) { + url += "&pack="; + url += rfc3986PercentEncode(setName); + } + const std::string num = normalizeCardNumber(setNo); + if (!num.empty()) { + url += "&card="; + url += rfc3986PercentEncode(num); + } + url += "&sort=name&sortdirection=asc"; + return url; +} + +Result +DigiBattle99CardPreviewSource::parseImageUrlFromSearch(const std::string& body, + std::string_view wantedCardName) { + using R = Result; + using K = PreviewLookupError::Kind; + try { + const auto j = nlohmann::json::parse(body); + if (j.is_object() && j.contains("error")) { + return R::err({K::NotFound, j.value("error", std::string{"No cards found."})}); + } + if (!j.is_array()) { + return R::err({K::Transient, "digimoncard.io Digi-Battle response is not a JSON array."}); + } + if (j.empty()) { + return R::err({K::NotFound, "digimoncard.io returned no matching Digi-Battle cards."}); + } + + const std::string wantedLower = toLower(trim(std::string(wantedCardName))); + const nlohmann::json* chosen = nullptr; + for (const auto& card : j) { + if (!wantedLower.empty()) { + const std::string cardName = trim(card.value("name", "")); + if (toLower(cardName) != wantedLower) continue; + } + chosen = &card; + break; + } + if (chosen == nullptr) { + return R::err({K::NotFound, "digimoncard.io returned no matching Digi-Battle cards."}); + } + const std::string id = normalizeCardNumber(chosen->value("id", "")); + if (id.empty()) { + return R::err({K::NotFound, "Digi-Battle card has no id / card number."}); + } + return R::ok(buildImageUrl(id)); + } catch (const std::exception& e) { + return R::err({K::Transient, + std::string("digimoncard.io Digi-Battle JSON parse error: ") + e.what()}); + } +} + +Result +DigiBattle99CardPreviewSource::fetchImageUrl(std::string_view name, + std::string_view setName, + std::string_view setNo) { + using R = Result; + using K = PreviewLookupError::Kind; + + const std::string num = normalizeCardNumber(setNo); + if (!num.empty()) { + return R::ok(buildImageUrl(num)); + } + if (name.empty()) { + return R::err({K::NotFound, "Digi-Battle preview requires a card name or set number."}); + } + + const std::string url = buildSearchUrl(name, setName, ""); + auto resp = http_.get(url); + if (!resp) return R::err({K::Transient, resp.error()}); + return parseImageUrlFromSearch(resp.value(), name); +} + +Result> DigiBattle99CardPreviewSource::parsePrintVariants( + const std::string& body, + std::string_view setName, + std::string_view wantedCardName) { + using R = Result>; + try { + const auto j = nlohmann::json::parse(body); + if (j.is_object() && j.contains("error")) { + return R::err(j.value("error", std::string{"No cards found."})); + } + if (!j.is_array() || j.empty()) { + return R::err("digimoncard.io returned no matching Digi-Battle cards."); + } + + const std::string wantedPack = trim(std::string(setName)); + const std::string wantedNameLower = toLower(trim(std::string(wantedCardName))); + + std::vector collected; + for (const auto& card : j) { + if (!wantedNameLower.empty()) { + const std::string cardName = trim(card.value("name", "")); + if (toLower(cardName) != wantedNameLower) continue; + } + if (!cardInPack(card, wantedPack)) continue; + AutoDetectedPrint out; + out.setNo = normalizeCardNumber(card.value("id", "")); + out.rarity = ""; // Digi-Battle UI is Pokémon-like; rarity not persisted. + if (out.setNo.empty()) continue; + collected.push_back(std::move(out)); + } + + if (collected.empty()) { + if (!wantedNameLower.empty() && !wantedPack.empty()) { + return R::err("Could not auto-detect Digi-Battle set print metadata."); + } + return R::err("digimoncard.io returned no matching Digi-Battle cards."); + } + + std::vector deduped; + deduped.reserve(collected.size()); + std::unordered_set seen; + seen.reserve(collected.size() * 2); + for (auto& p : collected) { + if (seen.insert(p.setNo).second) deduped.push_back(std::move(p)); + } + return R::ok(std::move(deduped)); + } catch (const std::exception& e) { + return R::err(std::string("digimoncard.io Digi-Battle JSON parse error: ") + e.what()); + } +} + +Result DigiBattle99CardPreviewSource::detectFirstPrint( + std::string_view name, + std::string_view setName) { + auto list = detectPrintVariants(name, setName); + if (!list || list.value().empty()) { + if (!list) return Result::err(list.error()); + return Result::err("Could not auto-detect Digi-Battle set print metadata."); + } + return Result::ok(list.value().front()); +} + +Result> DigiBattle99CardPreviewSource::detectPrintVariants( + std::string_view name, + std::string_view setName) { + using R = Result>; + const std::string url = buildSearchUrl(name, setName, ""); + auto resp = http_.get(url); + if (resp) { + return parsePrintVariants(resp.value(), setName, name); + } + // Retry name-only; still filter by pack in parsePrintVariants. + const std::string fallbackUrl = buildSearchUrl(name, "", ""); + auto fallback = http_.get(fallbackUrl); + if (!fallback) return R::err(fallback.error()); + return parsePrintVariants(fallback.value(), setName, name); +} + +} // namespace ccm diff --git a/core/src/games/digibattle99/DigiBattle99GameModule.cpp b/core/src/games/digibattle99/DigiBattle99GameModule.cpp new file mode 100644 index 0000000..a938f0e --- /dev/null +++ b/core/src/games/digibattle99/DigiBattle99GameModule.cpp @@ -0,0 +1,8 @@ +#include "ccm/games/digibattle99/DigiBattle99GameModule.hpp" + +namespace ccm { + +DigiBattle99GameModule::DigiBattle99GameModule(IHttpClient& http) + : setSource_(http), previewSource_(http) {} + +} // namespace ccm diff --git a/core/src/games/digibattle99/DigiBattle99SetSource.cpp b/core/src/games/digibattle99/DigiBattle99SetSource.cpp new file mode 100644 index 0000000..c02b7d3 --- /dev/null +++ b/core/src/games/digibattle99/DigiBattle99SetSource.cpp @@ -0,0 +1,119 @@ +#include "ccm/games/digibattle99/DigiBattle99SetSource.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace ccm { + +namespace { + +// Curated EN release dates for the vintage Digi-Battle product line. +// Series 1 Starter is verified 1999-06-01; other entries use digimoncard.io / +// checklist years (day unknown -> YYYY/01/01 or mid-year anchors for ordering). +const std::unordered_map& curatedReleaseDates() { + static const std::unordered_map kDates{ + {"Series 1 Starter Set", "1999/06/01"}, + {"Series 1 Booster Pack", "1999/06/01"}, + {"Series 2 Booster Pack", "1999/09/01"}, + {"Series 3 Booster Pack", "2000/01/01"}, + {"Series 4 Booster Pack", "2000/06/01"}, + {"Series 5 Booster Pack", "2000/10/01"}, + {"Series 6 Booster Pack", "2001/01/01"}, + {"Street Starter Set 1", "2001/01/01"}, + {"Street Starter Set 2", "2001/02/01"}, + {"Street Starter Set 3", "2001/03/01"}, + {"Street Starter Set 4", "2001/04/01"}, + {"Digimon The Movie Promo Cards", "2000/10/01"}, + }; + return kDates; +} + +std::string releaseDateForPack(const std::string& packName) { + const auto& dates = curatedReleaseDates(); + const auto it = dates.find(packName); + if (it != dates.end()) return it->second; + return {}; +} + +} // namespace + +DigiBattle99SetSource::DigiBattle99SetSource(IHttpClient& http) : http_(http) {} + +std::string DigiBattle99SetSource::slugifyPackName(std::string_view packName) { + std::string out; + out.reserve(packName.size()); + bool pendingHyphen = false; + for (unsigned char ch : packName) { + if (std::isalnum(ch)) { + if (pendingHyphen && !out.empty()) out.push_back('-'); + pendingHyphen = false; + out.push_back(static_cast(std::tolower(ch))); + } else { + pendingHyphen = !out.empty(); + } + } + return out; +} + +Result> DigiBattle99SetSource::parseResponse(const std::string& body) { + try { + const auto j = nlohmann::json::parse(body); + if (j.is_object() && j.contains("error")) { + return Result>::err( + j.value("error", std::string{"digimoncard.io set search error"})); + } + if (!j.is_array()) { + return Result>::err( + "digimoncard.io Digi-Battle response is not a JSON array."); + } + + // Preserve first-seen order of pack names, then sort by release date. + std::unordered_set seen; + std::vector packNames; + packNames.reserve(16); + for (const auto& entry : j) { + if (!entry.contains("set_name") || !entry.at("set_name").is_array()) continue; + for (const auto& pack : entry.at("set_name")) { + if (!pack.is_string()) continue; + const std::string name = pack.get(); + if (name.empty()) continue; + if (seen.insert(name).second) packNames.push_back(name); + } + } + + std::vector out; + out.reserve(packNames.size()); + for (const auto& name : packNames) { + Set s; + s.id = slugifyPackName(name); + s.name = name; + s.releaseDate = releaseDateForPack(name); + if (s.id.empty()) continue; + out.push_back(std::move(s)); + } + + std::sort(out.begin(), out.end(), [](const Set& a, const Set& b) { + if (a.releaseDate.empty() && !b.releaseDate.empty()) return false; + if (!a.releaseDate.empty() && b.releaseDate.empty()) return true; + if (a.releaseDate != b.releaseDate) return a.releaseDate < b.releaseDate; + return a.name < b.name; + }); + return Result>::ok(std::move(out)); + } catch (const std::exception& e) { + return Result>::err( + std::string("digimoncard.io Digi-Battle JSON parse error: ") + e.what()); + } +} + +Result> DigiBattle99SetSource::fetchAll() { + auto resp = http_.get(kEndpoint); + if (!resp) return Result>::err(resp.error()); + return parseResponse(resp.value()); +} + +} // namespace ccm diff --git a/core/src/services/CardFilter.cpp b/core/src/services/CardFilter.cpp index 24d02d7..47ea555 100644 --- a/core/src/services/CardFilter.cpp +++ b/core/src/services/CardFilter.cpp @@ -67,4 +67,19 @@ bool matchesYuGiOhFilter(const YuGiOhCard& card, std::string_view filter) { return false; } +bool matchesDigiBattle99Filter(const DigiBattle99Card& card, std::string_view filter) { + if (filter.empty()) return true; + + const std::string needle = asciiLower(filter); + + if (containsLower(card.name, needle)) return true; + if (containsLower(card.set.name, needle)) return true; + if (containsLower(card.setNo, needle)) return true; + if (containsLower(to_string(card.language), needle)) return true; + if (containsLower(to_string(card.condition), needle)) return true; + if (containsLower(std::to_string(card.amount), needle)) return true; + if (containsLower(card.note, needle)) return true; + return false; +} + } // namespace ccm diff --git a/core/src/services/CardSorter.cpp b/core/src/services/CardSorter.cpp index a6584e5..26da5a3 100644 --- a/core/src/services/CardSorter.cpp +++ b/core/src/services/CardSorter.cpp @@ -223,4 +223,74 @@ void sortYuGiOhCards(std::vector& cards, YuGiOhSortColumn column, } } +void sortDigiBattle99Cards(std::vector& cards, + DigiBattle99SortColumn column, + bool ascending) { + switch (column) { + case DigiBattle99SortColumn::Name: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return asciiLower(a.name) < asciiLower(b.name); + }, ascending)); + break; + case DigiBattle99SortColumn::SetReleaseDate: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return asciiLower(a.set.releaseDate) < + asciiLower(b.set.releaseDate); + }, ascending)); + break; + case DigiBattle99SortColumn::Language: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return asciiLower(to_string(a.language)) < + asciiLower(to_string(b.language)); + }, ascending)); + break; + case DigiBattle99SortColumn::Condition: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return asciiLower(to_string(a.condition)) < + asciiLower(to_string(b.condition)); + }, ascending)); + break; + case DigiBattle99SortColumn::Amount: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return a.amount < b.amount; + }, ascending)); + break; + case DigiBattle99SortColumn::Holo: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return a.holo < b.holo; + }, ascending)); + break; + case DigiBattle99SortColumn::FirstEdition: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return a.firstEdition < b.firstEdition; + }, ascending)); + break; + case DigiBattle99SortColumn::Signed: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return a.signed_ < b.signed_; + }, ascending)); + break; + case DigiBattle99SortColumn::Altered: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return a.altered < b.altered; + }, ascending)); + break; + case DigiBattle99SortColumn::Note: + std::stable_sort(cards.begin(), cards.end(), directional( + [](const DigiBattle99Card& a, const DigiBattle99Card& b) { + return asciiLower(a.note) < asciiLower(b.note); + }, ascending)); + break; + } +} + } // namespace ccm diff --git a/docs/AGENTS.md b/docs/AGENTS.md index ff0f8f0..6a16589 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -11,13 +11,13 @@ Long-form contributor documentation that lives outside the source tree. - `dow-doc-build-locally.md` — complete local build/setup reference for Windows and Linux, including dependency management and troubleshooting. - `intro-to-new-developers.md` — onboarding map for new contributors: architecture, folder responsibilities, guardrails, anti-patterns, and links to deeper docs. - `testing-and-test-code-of-conduct.md` — testing workflow plus expected standards for writing and maintaining deterministic, hermetic, behavior-focused tests. -- `assets-and-info-apis.md` — reference for the external info APIs (set metadata) and asset APIs (card preview images) used by the Magic, Pokémon, and Yu-Gi-Oh! modules, plus the runtime flow through `SetService` / `CardPreviewService`, shared HTTP defaults (`CprHttpClient`, `Accept: */*`), per-game card-back fallbacks (URLs + bundled `ygo_card_back.png`), and error-surface conventions. The Yu-Gi-Oh! **Info API** section also documents the local **set code** lookup used by the edit dialog (`YuGiOhSetLookup`, no extra HTTP). +- `assets-and-info-apis.md` — reference for the external info APIs (set metadata) and asset APIs (card preview images) used by the Magic, Pokémon, Yu-Gi-Oh!, and Digimon Digi-Battle modules, plus the runtime flow through `SetService` / `CardPreviewService`, shared HTTP defaults (`CprHttpClient`, `Accept: */*`), per-game card-back fallbacks (URLs + bundled `ygo_card_back.png` / `digibattle99_card_back.png`), and error-surface conventions. The Yu-Gi-Oh! **Info API** section also documents the local **set code** lookup used by the edit dialog (`YuGiOhSetLookup`, no extra HTTP). - `caching.md` — dedicated reference for preview-byte caching tiers (`CardPreviewService` LRU + `LocalPreviewByteCache`), cache keys and eviction, HTTP session reuse via `CprHttpClient`, and explicit non-goals (no error caching). - `README.md` — index page that clusters docs by area and links to all documents in this directory. ## Subdirectories -- `assets/images/` — static screenshots and other binary assets referenced from the documentation (currently `demo-mtg.png`, `demo-pkm.png`). Keep filenames stable so cross-doc links don't break, and prefer compressed PNG/JPEG over uncompressed formats. +- `assets/images/` — static screenshots and other binary assets referenced from the documentation (currently `demo-mtg.png`, `demo-pkm.png`, `demo-ygo.png`, `demo-digibattle99.png`). Keep filenames stable so cross-doc links don't break, and prefer compressed PNG/JPEG over uncompressed formats. ## Conventions @@ -28,7 +28,7 @@ Long-form contributor documentation that lives outside the source tree. ## Required follow-ups - After changing per-game seams in `core/` (e.g. `IGameModule`, `ISetSource`, `ICardPreviewSource`, `CollectionService`, `SetService`, `CardPreviewService`, `ImageService`) you **must** update `adding-a-new-game.md` to keep the canonical procedure in sync. The same applies to the UI seams (`IGameView`, `BaseCardListPanel`, `BaseCardEditDialog`, `BaseSelectedCardPanel`) and the composition-root wiring in `app/main.cpp`. -- After changing any game's set/preview adapters (`MagicSetSource`, `MagicCardPreviewSource`, `PokemonSetSource`, `PokemonCardPreviewSource`, `YuGiOhSetSource`, `YuGiOhCardPreviewSource`) — endpoints, response parsing, name/number normalization, or the info-vs-asset split — you **must** update `assets-and-info-apis.md` so the API reference matches the live behavior. +- After changing any game's set/preview adapters (`MagicSetSource`, `MagicCardPreviewSource`, `PokemonSetSource`, `PokemonCardPreviewSource`, `YuGiOhSetSource`, `YuGiOhCardPreviewSource`, `DigiBattle99SetSource`, `DigiBattle99CardPreviewSource`) — endpoints, response parsing, name/number normalization, or the info-vs-asset split — you **must** update `assets-and-info-apis.md` so the API reference matches the live behavior. - After bumping a key dependency (`nlohmann/json`, `cpr`, `wxWidgets`, `doctest`) in a way that changes a public API used in the guide's examples, update those examples. - After adding a new file under `docs/` (or a new entry under `docs/assets/images/`) you **must** add it to the file list above **and** to `README.md` so the index stays complete. - Do **not** rename, move, or split this file without first updating every other `AGENTS.md` that points at it (root, `core/`, `ui_wx/`, `app/`, `tests/`). diff --git a/docs/README.md b/docs/README.md index ac791f5..fdf46af 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,7 +22,7 @@ This folder contains contributor documentation for Card Collection Manager 3. St - [adding-a-new-game.md](adding-a-new-game.md): canonical end-to-end procedure for adding a new game module across `core/`, `ui_wx/`, and `app/`. -- [assets-and-info-apis.md](assets-and-info-apis.md): external info and asset APIs used by Magic, Pokémon, and Yu-Gi-Oh! modules, preview fallback URLs / bundled YGO card-back asset, and shared HTTP behavior (`CprHttpClient`). +- [assets-and-info-apis.md](assets-and-info-apis.md): external info and asset APIs used by Magic, Pokémon, Yu-Gi-Oh!, and Digimon Digi-Battle modules, preview fallback URLs / bundled card-back assets, and shared HTTP behavior (`CprHttpClient`). ## Performance & Caching diff --git a/docs/assets-and-info-apis.md b/docs/assets-and-info-apis.md index cb1c070..6658311 100644 --- a/docs/assets-and-info-apis.md +++ b/docs/assets-and-info-apis.md @@ -78,6 +78,43 @@ Used in two situations: YGOPRODeck publishes rate limits and asks clients to cache responses and avoid abusive hotlinking; treat failures after burst traffic as an upstream policy signal, not an app bug. Yugipedia’s MediaWiki API is similarly polite — one batched call per preview lookup keeps us well under any normal threshold. +## Digimon Digi-Battle (1999) APIs (digimoncard.io) + +English Digi-Battle is wired as `Game::DigiBattle99` (`dirName` `digibattle99`, UI label **Digimon (Digi-Battle)**). Upstream docs: [digimoncard.io Public API](https://digimoncard.io/api-documentation). Always scope requests with `series=Digimon Digi-Battle Card Game` so modern Digimon Card Game rows are never mixed in. Rate limit: **15 requests / 10 seconds / IP** (429 then temporary block on abuse). + +### Info API: derived set list from `search.php` + +There is **no** dedicated sets endpoint. `DigiBattle99SetSource` calls: + +`https://digimoncard.io/api-public/search.php?series=Digimon%20Digi-Battle%20Card%20Game&limit=1000&sort=name&sortdirection=asc` + +and collects unique `set_name[]` pack strings. Each pack becomes a `Set` with: + +- `Set.name` — exact pack display name (used as `pack=` on search / auto-detect) +- `Set.id` — stable slug (`Series 1 Starter Set` → `series-1-starter-set`); never rename after ship +- `Set.releaseDate` — curated table in the set source (Series 1 Starter = `1999/06/01` verified; other packs use documented year/month anchors) + +Unknown future packs get an empty release date and sort last. + +### Asset API: CDN images + `search.php` lookup + +Card scans live at: + +`https://images.digimoncard.io/images/cards/{id}.jpg` + +where `{id}` is the API card number (`ST-01`, `BO-115`, `MO-06`). The CDN also serves `.webp`, but CCM3 uses `.jpg` because `OnInit` only registers `wxPNGHandler` / `wxJPEGHandler` (WebP bytes would surface as “image decode failed”). + +`DigiBattle99CardPreviewSource::fetchImageUrl`: + +1. If `setNo` is non-empty → normalize alphabetic prefix to uppercase (**no** invented zero-padding) and return the CDN URL with **no** search round-trip. +2. Otherwise search with `n=` + optional `pack=` (display set name) + `series=`, take the first exact name match’s `id`, then build the CDN URL. + +**Preview key:** `(name, set.name, setNo)` — middle slot is the pack **display name** (same idea as Yu-Gi-Oh! passing `set.name` for YGOPRODeck `cardset=`), not the slug id. + +**Auto-detect** (`detectPrintVariants`): same search; distinct `id` values become `AutoDetectedPrint::setNo`. Digi-Battle UI is Pokémon-like (no persisted rarity). + +Empty search array / `{"error":"..."}` → `NotFound`; bad JSON / HTTP → `Transient`. + ## Runtime Flow In CCM3 The app uses the same flow for every game that registers a module: @@ -91,15 +128,15 @@ The app uses the same flow for every game that registers a module: See [caching.md](caching.md) for a dedicated reference on preview cache tiers, internal keys, eviction, clearing, and HTTP session reuse. -Three mechanisms reduce preview latency for **all** games (Magic, Pokemon, Yu-Gi-Oh!). In addition, the shared HTTP session speeds **every** `IHttpClient::get` call (including set-list fetches), not only previews: +Three mechanisms reduce preview latency for **all** games (Magic, Pokemon, Yu-Gi-Oh!, DigiBattle99). In addition, the shared HTTP session speeds **every** `IHttpClient::get` call (including set-list fetches), not only previews: - **In-memory preview LRU** (`CardPreviewService`). Successful `fetchPreviewBytes` results are cached keyed by `(game, name, setId, setNo)`; successful `fetchImageBytesByUrl` results are cached keyed by URL (used for the per-game card-back fallback). Re-selecting a previously viewed row is decode-only — no HTTP at all. The cache is bounded by `CardPreviewService::kCacheCapacity` (currently 128 entries) and uses a list+map LRU under a mutex (the preview pipeline is invoked from a worker thread in `BaseSelectedCardPanel`). **Source errors are split** by `PreviewLookupError::Kind`: `NotFound` (the upstream answered cleanly that the record has no image) is *negative-cached* in this tier so subsequent selections short-circuit without HTTP, while `Transient` (HTTP/network/parse failures) is **never** cached so a brief outage cannot permanently disable a card's preview. - **Persistent disk byte cache** (`LocalPreviewByteCache`, port `IPreviewByteCache`). Wraps the in-memory tier with an on-disk store under `/.cache/preview-cache/` — pinned **next to the executable**, in the same scope as `config.json`, **not** under the user-configurable `Configuration.dataStorage` path. The cache stays put when the user reconfigures or relocates their collection data, and it is not part of the user's data directory backups; it is install-scoped, not collection-scoped. Both positive previews and `NotFound` verdicts survive an app restart. Each entry is a mutually-exclusive `.bin` (positive payload) or `.neg` (negative marker) plus a `.idx` sidecar containing the original key — load-time mismatch on the sidecar treats the entry as a miss, so a hash collision degrades to a one-time HTTP refetch instead of serving the wrong card's bytes (or the wrong card's "no image" verdict). Hashing is FNV-1a 64-bit (no crypto dependency). The cache is bounded by total `.bin` payload bytes (default `kDefaultMaxBytes = 64 MiB`) and evicts oldest entries by mtime when a new write would exceed the cap; reading an entry touches its mtime so frequently-viewed cards survive eviction. Negative `.neg` markers are tiny and not counted against the cap — their count is naturally bounded by the user's actively-viewed records. Filesystem mutations route through `IFileSystem`; size and mtime queries (which the port does not expose) use `std::filesystem` directly inside the adapter. The persistent tier is **fire-and-forget on the way down** — every adapter operation swallows I/O errors so a flaky or full disk never breaks the preview path. -- **Persistent HTTP session** (`CprHttpClient`). The adapter owns one long-lived `cpr::Session` (libcurl easy handle) for the lifetime of the app. Per-request configuration is limited to `SetUrl(...)`; headers, timeout, and redirect policy are configured once in the constructor. Default **`Accept: */*`** keeps JSON responses and raw image bodies working on the same session (avoid tying every GET to `application/json`). libcurl's connection pool keeps the TLS connection to each host warm, so repeat calls to `api.scryfall.com`, `api.pokemontcg.io`, `db.ygoprodeck.com`, `yugipedia.com`, and `ms.yugipedia.com` skip the TLS handshake. A `std::mutex` serializes callers — libcurl easy handles are not thread-safe, and the preview pipeline is single-flight per panel anyway. +- **Persistent HTTP session** (`CprHttpClient`). The adapter owns one long-lived `cpr::Session` (libcurl easy handle) for the lifetime of the app. Per-request configuration is limited to `SetUrl(...)`; headers, timeout, and redirect policy are configured once in the constructor. Default **`Accept: */*`** keeps JSON responses and raw image bodies working on the same session (avoid tying every GET to `application/json`). libcurl's connection pool keeps the TLS connection to each host warm, so repeat calls to `api.scryfall.com`, `api.pokemontcg.io`, `db.ygoprodeck.com`, `yugipedia.com`, `ms.yugipedia.com`, `digimoncard.io`, and `images.digimoncard.io` skip the TLS handshake. A `std::mutex` serializes callers — libcurl easy handles are not thread-safe, and the preview pipeline is single-flight per panel anyway. `CardPreviewService` consults the tiers in order **memory → disk → source/HTTP**. On a disk hit (positive *or* negative) the entry is promoted into the in-memory LRU so the next click on the same row never re-touches the disk cache. On HTTP success the bytes are written through to both tiers in one shot. On a `NotFound` source error the **negative** marker is written through to both tiers; on `Transient` source errors nothing is written, so the next selection retries cleanly. -The combined effect on the preview path: first selection of a previously-unseen card pays one TLS handshake per *new* host this session (typically two hops for Yu-Gi-Oh!: `yugipedia.com` for the API, `ms.yugipedia.com` for the image), each subsequent fresh card on the same host skips the handshake, any re-selection of an already-viewed card is instant, after the first run with the disk cache populated **even a fresh app launch is decode-only for previously-seen cards** until eviction or a manual cache clear, and **records the upstream cleanly has no image for** stay "instant card-back" across restarts instead of re-paying the lookup every launch. Editing a lookup-relevant field of a record (name, set, setNo, or for Yu-Gi-Oh! the rarity / edition packed into setNo) changes the cache key automatically, so a fresh resolution attempt happens on the next click. +The combined effect on the preview path: first selection of a previously-unseen card pays one TLS handshake per *new* host this session (typically two hops for Yu-Gi-Oh!: `yugipedia.com` for the API, `ms.yugipedia.com` for the image; Digi-Battle often hits `images.digimoncard.io` only when `setNo` is already known), each subsequent fresh card on the same host skips the handshake, any re-selection of an already-viewed card is instant, after the first run with the disk cache populated **even a fresh app launch is decode-only for previously-seen cards** until eviction or a manual cache clear, and **records the upstream cleanly has no image for** stay "instant card-back" across restarts instead of re-paying the lookup every launch. Editing a lookup-relevant field of a record (name, set, setNo, or for Yu-Gi-Oh! the rarity / edition packed into setNo) changes the cache key automatically, so a fresh resolution attempt happens on the next click. To clear the persistent cache (for example to recover from a bad upstream image), delete the `/.cache/preview-cache/` subdirectory or the umbrella `/.cache/` folder. Note: the in-app "Reset" / data-storage-relocation flow does **not** touch this directory — the cache is install-scoped, not collection-scoped, so it is preserved across data-dir moves and only cleared by deleting the directory above explicitly (or by reinstalling / relocating the executable). @@ -110,6 +147,7 @@ Fallback card-back sources (`BaseSelectedCardPanel`; Magic/Pokémon URLs match C - Magic: `https://gamepedia.cursecdn.com/mtgsalvation_gamepedia/f/f8/Magic_card_back.jpg` - Pokémon: `https://archives.bulbagarden.net/media/upload/1/17/Cardback.jpg` - Yu-Gi-Oh!: Yugipedia English TCG back — try `https://ms.yugipedia.com/thumb/e/e5/Back-EN.png/250px-Back-EN.png`, then `https://ms.yugipedia.com/e/e5/Back-EN.png`; if both fail, load `/assets/ygo_card_back.png` (shipped from `ui_wx/assets/ygo_card_back.png` at link time). `fallbackImageUrlForGame(Game::YuGiOh)` returns the thumbnail URL for helpers that only consult a single string. +- Digimon (Digi-Battle): no stable public back URL; load `/assets/digibattle99_card_back.png` (shipped from `ui_wx/assets/digibattle99_card_back.png` at link time). If a game module does not provide a preview source (`cardPreviewSource() == nullptr`), preview registration is skipped and the UI behaves as "no remote preview API available." @@ -120,6 +158,6 @@ All source types return `Result` errors so failures cross bounda - info API failures (bad set payload, schema mismatch, endpoint/network failure), and - asset API failures (query mismatch, no matching card, missing image fields, image download failure). -When previews fail, verify request construction first (name sanitization, number normalization, percent encoding), then verify response shape assumptions: Scryfall (`data`, `image_uris`), Pokemon (`data`, `images.large`/`images.small`; auto-detect also needs `name`, `number`, `rarity`, and `set.id` on each matching row), Yu-Gi-Oh! Yugipedia (`query.pages..imageinfo[0].url` per filename, missing files tagged `"missing": ""`), Yu-Gi-Oh! YGOPRODeck fallback (`data`, `name`, `card_images`). If the UI fallback path succeeds (network card-back and/or bundled PNG), the panel shows the card-back image and the inline label `(image preview unavailable)`; only if every fallback fails does the preview stay empty with status text. +When previews fail, verify request construction first (name sanitization, number normalization, percent encoding), then verify response shape assumptions: Scryfall (`data`, `image_uris`), Pokemon (`data`, `images.large`/`images.small`; auto-detect also needs `name`, `number`, `rarity`, and `set.id` on each matching row), Yu-Gi-Oh! Yugipedia (`query.pages..imageinfo[0].url` per filename, missing files tagged `"missing": ""`), Yu-Gi-Oh! YGOPRODeck fallback (`data`, `name`, `card_images`), Digi-Battle digimoncard.io (top-level array with `name`/`id`/`set_name`; CDN `images.digimoncard.io/images/cards/{id}.jpg`). If the UI fallback path succeeds (network card-back and/or bundled PNG), the panel shows the card-back image and the inline label `(image preview unavailable)`; only if every fallback fails does the preview stay empty with status text. For Yu-Gi-Oh! specifically, when a printing shows the wrong art compared with Yugipedia’s gallery, debug in this order: (1) verify the candidate list via `YuGiOhCardPreviewSource::buildCandidateFilenames(...)` against the actual file names on Yugipedia’s `Card_Gallery:` page; (2) confirm the dialog rarity name maps to the expected short code in `ygoRarityShortCode(...)` / `rarityCodeFor(...)` (extend the mapping when a new rarity surfaces); (3) confirm the `firstEdition` flag matches the printed edition stamp — the candidate ordering puts the printed edition first. diff --git a/docs/assets/images/demo-digibattle99.png b/docs/assets/images/demo-digibattle99.png new file mode 100644 index 0000000000000000000000000000000000000000..7bb131e48b4b868161311bc0e3909d6f956502b8 GIT binary patch literal 270066 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

  • l&0 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. The user editing **any** lookup-relevant field of a card record produces a **different cache key** for the resulting selection, which means: +The cache key for the preview path is `(game, name, setId, setNo)`. For Yu-Gi-Oh! the third slot also encodes rarity and edition, packed by `YuGiOhSelectedCardPanel::previewKey()` as `||||<1E|UE>`. For Digimon Digi-Battle the middle slot is the pack **display name** (`Set.name`), not the slug id, so `pack=` search and the CDN path stay aligned. The user editing **any** lookup-relevant field of a card record produces a **different cache key** for the resulting selection, which means: - Memory and disk lookups for the new key **miss** the old entry (positive or negative). - A fresh `ICardPreviewSource::fetchImageUrl` call runs. diff --git a/tests/AGENTS.md b/tests/AGENTS.md index 66fddcb..1f18a9f 100644 --- a/tests/AGENTS.md +++ b/tests/AGENTS.md @@ -21,9 +21,11 @@ - `std_file_system_tests.cpp` — `StdFileSystem` directly (`exists`, `isDirectory`, `ensureDirectory`, `readText`, `writeText`, `copyFile`, `remove`, `listDirectory`) under a unique `temp_directory_path()/ccm_std_fs_test_*` directory per case; scope matches the real-disk exception documented for preview-cache tests. - `pokemon_set_source_tests.cpp` — `PokemonSetSource::parseResponse` (api.pokemontcg.io/v2/sets shape — `data[].id`, `name`, `releaseDate` already in `YYYY/MM/DD`) + sort-by-release-date stability. Drives `fetchAll` via `FixedHttpClient` and asserts the public endpoint URL. - `pokemon_card_preview_source_tests.cpp` — `PokemonCardPreviewSource::buildSearchUrl` (percent-encoded `name:` / `set.id:` / `number:` triple, with collector-number `4/102` -> `4` normalization) + `parseResponse` (`data[0].images.large` with `images.small` fallback). Drives `fetchImageUrl` via `FixedHttpClient`. +- `digibattle99_set_source_tests.cpp` — `DigiBattle99SetSource::parseResponse` derives unique packs from digimoncard.io search arrays, slugifies `Set.id`, applies curated release dates, and sorts chronologically. Drives `fetchAll` via `FixedHttpClient`. +- `digibattle99_card_preview_source_tests.cpp` — CDN image URL from `setNo`, search URL encoding (`series`/`n`/`pack`/`card`), `parseImageUrlFromSearch` NotFound vs Transient, and auto-detect print variants. Drives `fetchImageUrl` / `detectPrintVariants` via `FixedHttpClient`. - `yugioh_set_source_tests.cpp` — `YuGiOhSetSource::parseResponse` for YGOPRODeck `cardsets.php` (`set_code`, `set_name`, `tcg_date`) including `YYYY-MM-DD` -> `YYYY/MM/DD` rewrite and chronological sort checks. - `yugioh_set_lookup_tests.cpp` — `lookupYuGiOhSetByShorthand` / helpers in `ccm/util/YuGiOhSetLookup.hpp` (trim, ASCII case-fold, exact `Set.id` match, not-found vs ambiguous). -- `game_module_tests.cpp` — smoke tests that each concrete `IGameModule` (Magic / Pokemon / Yu-Gi-Oh) reports stable `id()`, `dirName()`, `displayName()`, and a non-null `cardPreviewSource()` when constructed with a noop `IHttpClient`. +- `game_module_tests.cpp` — smoke tests that each concrete `IGameModule` (Magic / Pokemon / Yu-Gi-Oh / DigiBattle99) reports stable `id()`, `dirName()`, `displayName()`, and a non-null `cardPreviewSource()` when constructed with a noop `IHttpClient`. - `yugioh_card_preview_source_tests.cpp` — `YuGiOhCardPreviewSource` Yugipedia + YGOPRODeck unit coverage. Helper-level tests pin down `normalizeName` (whitespace + Yugipedia-policy punctuation stripping), `ygoRarityShortCode` + `rarityCodeFor` (CCM3 dialog rarity names → canonical short codes used by both the YGO overview table and Yugipedia filename generation; unknown rarity falls through), `extractSetCode` (`LOB-005` / `LOB-DE005` → `LOB`), `buildCandidateFilenames` (printed-edition first, EN/NA/EU/AU + png/jpg, rarity-less fallback round, empty list when slug or set code is missing), `buildYugipediaQueryUrl` (single `titles=File:A|File:B` batch, percent-encoded), and `parseYugipediaResponse` (returns the URL of the highest-priority filename that resolved, errors when every candidate is `missing`). End-to-end `fetchImageUrl` cases use a `RoutingHttpClient` to verify Yugipedia is queried first and the per-printing scan is returned when found, that empty/error Yugipedia responses fall through to the YGOPRODeck `card_images[0]` fallback, that the YGOPRODeck error is propagated when both upstreams fail, and that an empty `setNo` skips Yugipedia entirely. `parseFirstPrint` preferred-`set_name` lookup is also covered for the auto-detect path. `parsePrintVariants` includes synthetic scenarios aligned with the `yugioh_same_card_set_variant_tests` fixture (dual-rarity vs multi-code within one display set, duplicate suppression, and no merge across unrelated `set_name` rows when the picker label matches nothing). - `card_sorter_tests.cpp` — `sortMagicCards` / `sortPokemonCards` per-column behavior. Pin-down tests for `byField`-equivalent semantics: case-insensitive strings, chronological set sort via `set.releaseDate`, numeric `amount`, `false < true` boolean order, stable composition (sort by name then by set keeps inner-name order). Update this file whenever you add a new column / sort key. - `card_filter_tests.cpp` — `matchesMagicFilter` / `matchesPokemonFilter` / `matchesYuGiOhFilter` row-matcher behavior. Pin-down tests for `applyFilter`-equivalent semantics: case-insensitive substring match across `tableFields` valueKeys (name, set.name, language, condition, amount-as-string, note; Pokemon adds `setNo`; Yu-Gi-Oh adds `setNo` + `rarity`), boolean flag columns intentionally excluded, empty filter matches everything. Update this file whenever you add a new searchable column. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index badd60a..7e67aee 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,8 @@ add_executable(ccm_core_tests std_file_system_tests.cpp pokemon_set_source_tests.cpp pokemon_card_preview_source_tests.cpp + digibattle99_set_source_tests.cpp + digibattle99_card_preview_source_tests.cpp icard_preview_source_tests.cpp yugioh_set_source_tests.cpp yugioh_set_lookup_tests.cpp diff --git a/tests/card_filter_tests.cpp b/tests/card_filter_tests.cpp index 9501a99..4927237 100644 --- a/tests/card_filter_tests.cpp +++ b/tests/card_filter_tests.cpp @@ -6,6 +6,7 @@ #include #include "ccm/domain/Enums.hpp" +#include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" #include "ccm/domain/YuGiOhCard.hpp" @@ -238,3 +239,40 @@ TEST_SUITE("CardFilter::matchesYuGiOhFilter") { CHECK_FALSE(matchesYuGiOhFilter(c, "zzznomatch")); } } + +TEST_SUITE("CardFilter::matchesDigiBattle99Filter") { + TEST_CASE("matches by name and set.name") { + DigiBattle99Card c; + c.name = "Agumon"; + c.set.name = "Series 1 Starter Set"; + CHECK(matchesDigiBattle99Filter(c, "agu")); + CHECK(matchesDigiBattle99Filter(c, "STARTER")); + CHECK_FALSE(matchesDigiBattle99Filter(c, "greymon")); + } + + TEST_CASE("includes setNo in searchable columns") { + DigiBattle99Card c; + c.name = "Agumon"; + c.set.name = "Series 1 Starter Set"; + c.setNo = "ST-01"; + CHECK(matchesDigiBattle99Filter(c, "st-01")); + CHECK(matchesDigiBattle99Filter(c, "ST-")); + } + + TEST_CASE("empty filter matches everything") { + DigiBattle99Card c; + c.name = "Agumon"; + CHECK(matchesDigiBattle99Filter(c, "")); + } + + TEST_CASE("boolean flag columns are not matched") { + DigiBattle99Card c; + c.name = "Agumon"; + c.holo = true; + c.firstEdition = true; + c.signed_ = true; + c.altered = true; + CHECK_FALSE(matchesDigiBattle99Filter(c, "true")); + CHECK(matchesDigiBattle99Filter(c, "agu")); + } +} diff --git a/tests/card_sorter_tests.cpp b/tests/card_sorter_tests.cpp index de5f8d4..e93c4af 100644 --- a/tests/card_sorter_tests.cpp +++ b/tests/card_sorter_tests.cpp @@ -6,6 +6,7 @@ #include #include "ccm/domain/Enums.hpp" +#include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" #include "ccm/domain/YuGiOhCard.hpp" @@ -94,6 +95,30 @@ YuGiOhCard yc(std::uint32_t id, std::string name, return c; } +DigiBattle99Card db(std::uint32_t id, std::string name, + std::string setName, std::string releaseDate, + std::uint8_t amount = 1, + bool holo = false, bool firstEdition = false, + bool sgnd = false, bool altered = false, + Language lang = Language::English, + Condition cond = Condition::NearMint, + std::string note = "") { + DigiBattle99Card c; + c.id = id; + c.name = std::move(name); + c.set.name = std::move(setName); + c.set.releaseDate = std::move(releaseDate); + c.amount = amount; + c.holo = holo; + c.firstEdition = firstEdition; + c.signed_ = sgnd; + c.altered = altered; + c.language = lang; + c.condition = cond; + c.note = std::move(note); + return c; +} + std::vector ids(const std::vector& v) { std::vector out; out.reserve(v.size()); @@ -115,6 +140,13 @@ std::vector ids(const std::vector& v) { return out; } +std::vector ids(const std::vector& v) { + std::vector out; + out.reserve(v.size()); + for (const auto& c : v) out.push_back(c.id); + return out; +} + } // namespace TEST_SUITE("CardSorter - Magic columns") { @@ -451,3 +483,35 @@ TEST_SUITE("CardSorter - YuGiOh columns") { CHECK(ids(v) == std::vector{3, 1, 2}); } } + +TEST_SUITE("CardSorter - DigiBattle99 columns") { + TEST_CASE("Holo and FirstEdition sort false before true") { + std::vector v = { + db(1, "a", "X", "2000/01/01", 1, /*holo=*/true, /*first=*/false), + db(2, "b", "X", "2000/01/01", 1, /*holo=*/false, /*first=*/true), + db(3, "c", "X", "2000/01/01", 1, /*holo=*/false, /*first=*/false), + }; + sortDigiBattle99Cards(v, DigiBattle99SortColumn::Holo, /*ascending=*/true); + CHECK(ids(v) == std::vector{2, 3, 1}); + sortDigiBattle99Cards(v, DigiBattle99SortColumn::FirstEdition, /*ascending=*/true); + CHECK(ids(v) == std::vector{3, 1, 2}); + } + + TEST_CASE("Set column sorts by release date") { + std::vector v = { + db(1, "x", "Late", "2001/01/01"), + db(2, "y", "Early", "1999/06/01"), + }; + sortDigiBattle99Cards(v, DigiBattle99SortColumn::SetReleaseDate, /*ascending=*/true); + CHECK(ids(v) == std::vector{2, 1}); + } + + TEST_CASE("Name sorts case-insensitively") { + std::vector v = { + db(1, "greymon", "X", "2000/01/01"), + db(2, "Agumon", "X", "2000/01/01"), + }; + sortDigiBattle99Cards(v, DigiBattle99SortColumn::Name, /*ascending=*/true); + CHECK(ids(v) == std::vector{2, 1}); + } +} diff --git a/tests/digibattle99_card_preview_source_tests.cpp b/tests/digibattle99_card_preview_source_tests.cpp new file mode 100644 index 0000000..2e88a92 --- /dev/null +++ b/tests/digibattle99_card_preview_source_tests.cpp @@ -0,0 +1,179 @@ +#include + +#include "ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp" +#include "ccm/ports/IHttpClient.hpp" + +#include + +using namespace ccm; + +namespace { + +class FixedHttpClient final : public IHttpClient { +public: + std::string lastUrl; + std::string body; + bool ok = true; + Result get(std::string_view url) override { + lastUrl = std::string(url); + return ok ? Result::ok(body) + : Result::err("offline"); + } +}; + +} // namespace + +TEST_SUITE("DigiBattle99CardPreviewSource::normalizeCardNumber") { + TEST_CASE("uppercases alphabetic prefix without zero-padding") { + CHECK(DigiBattle99CardPreviewSource::normalizeCardNumber("bo-88") == "BO-88"); + CHECK(DigiBattle99CardPreviewSource::normalizeCardNumber("st-01") == "ST-01"); + CHECK(DigiBattle99CardPreviewSource::normalizeCardNumber(" MO-06 ") == "MO-06"); + } +} + +TEST_SUITE("DigiBattle99CardPreviewSource::buildImageUrl") { + TEST_CASE("builds CDN jpeg URL from card id") { + CHECK(DigiBattle99CardPreviewSource::buildImageUrl("ST-01") == + "https://images.digimoncard.io/images/cards/ST-01.jpg"); + CHECK(DigiBattle99CardPreviewSource::buildImageUrl("bo-115") == + "https://images.digimoncard.io/images/cards/BO-115.jpg"); + } +} + +TEST_SUITE("DigiBattle99CardPreviewSource::buildSearchUrl") { + TEST_CASE("percent-encodes name pack and series") { + const auto url = DigiBattle99CardPreviewSource::buildSearchUrl( + "Agumon", "Series 1 Starter Set", ""); + CHECK(url.find("https://digimoncard.io/api-public/search.php?series=") == 0); + CHECK(url.find("Digimon%20Digi-Battle%20Card%20Game") != std::string::npos); + CHECK(url.find("&n=Agumon") != std::string::npos); + CHECK(url.find("&pack=Series%201%20Starter%20Set") != std::string::npos); + CHECK(url.find("&card=") == std::string::npos); + } + + TEST_CASE("includes card= when setNo is present") { + const auto url = DigiBattle99CardPreviewSource::buildSearchUrl( + "Agumon", "Series 1 Starter Set", "st-01"); + CHECK(url.find("&card=ST-01") != std::string::npos); + } + + TEST_CASE("empty pack omits pack clause") { + const auto url = + DigiBattle99CardPreviewSource::buildSearchUrl("Agumon", "", "ST-01"); + CHECK(url.find("&pack=") == std::string::npos); + CHECK(url.find("&card=ST-01") != std::string::npos); + } +} + +TEST_SUITE("DigiBattle99CardPreviewSource::parseImageUrlFromSearch") { + TEST_CASE("returns CDN URL for first exact name match") { + const std::string json = R"([ + {"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}, + {"name":"Agumon","id":"BO-115","set_name":["Series 1 Booster Pack"]} + ])"; + const auto out = + DigiBattle99CardPreviewSource::parseImageUrlFromSearch(json, "Agumon"); + REQUIRE(out.isOk()); + CHECK(out.value() == "https://images.digimoncard.io/images/cards/ST-01.jpg"); + } + + TEST_CASE("empty array is NotFound") { + const auto out = + DigiBattle99CardPreviewSource::parseImageUrlFromSearch("[]", "Agumon"); + REQUIRE(out.isErr()); + CHECK(out.error().kind == PreviewLookupError::Kind::NotFound); + } + + TEST_CASE("API error object is NotFound") { + const auto out = DigiBattle99CardPreviewSource::parseImageUrlFromSearch( + R"({"error":"No cards found for this search."})", "Agumon"); + REQUIRE(out.isErr()); + CHECK(out.error().kind == PreviewLookupError::Kind::NotFound); + } + + TEST_CASE("non-array is Transient") { + const auto out = + DigiBattle99CardPreviewSource::parseImageUrlFromSearch(R"({"meta":{}})", "Agumon"); + REQUIRE(out.isErr()); + CHECK(out.error().kind == PreviewLookupError::Kind::Transient); + } + + TEST_CASE("malformed JSON is Transient") { + const auto out = + DigiBattle99CardPreviewSource::parseImageUrlFromSearch("{not json", "Agumon"); + REQUIRE(out.isErr()); + CHECK(out.error().kind == PreviewLookupError::Kind::Transient); + } +} + +TEST_SUITE("DigiBattle99CardPreviewSource::fetchImageUrl") { + TEST_CASE("setNo present skips HTTP and returns CDN URL") { + FixedHttpClient http; + DigiBattle99CardPreviewSource src{http}; + const auto out = src.fetchImageUrl("Agumon", "Series 1 Starter Set", "st-01"); + REQUIRE(out.isOk()); + CHECK(out.value() == "https://images.digimoncard.io/images/cards/ST-01.jpg"); + CHECK(http.lastUrl.empty()); + } + + TEST_CASE("empty setNo searches and parses") { + FixedHttpClient http; + http.body = R"([{"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}])"; + DigiBattle99CardPreviewSource src{http}; + const auto out = src.fetchImageUrl("Agumon", "Series 1 Starter Set", ""); + REQUIRE(out.isOk()); + CHECK(out.value() == "https://images.digimoncard.io/images/cards/ST-01.jpg"); + CHECK(http.lastUrl.find("search.php") != std::string::npos); + CHECK(http.lastUrl.find("n=Agumon") != std::string::npos); + } + + TEST_CASE("HTTP failure is Transient") { + FixedHttpClient http; + http.ok = false; + DigiBattle99CardPreviewSource src{http}; + const auto out = src.fetchImageUrl("Agumon", "Series 1 Starter Set", ""); + REQUIRE(out.isErr()); + CHECK(out.error().kind == PreviewLookupError::Kind::Transient); + } +} + +TEST_SUITE("DigiBattle99CardPreviewSource::parsePrintVariants") { + TEST_CASE("collects distinct card ids for name+pack") { + const std::string json = R"([ + {"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}, + {"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}, + {"name":"Agumon","id":"BO-115","set_name":["Series 1 Booster Pack"]}, + {"name":"Greymon","id":"ST-02","set_name":["Series 1 Starter Set"]} + ])"; + const auto out = DigiBattle99CardPreviewSource::parsePrintVariants( + json, "Series 1 Starter Set", "Agumon"); + REQUIRE(out.isOk()); + REQUIRE(out.value().size() == 1); + CHECK(out.value()[0].setNo == "ST-01"); + } + + TEST_CASE("pack miss with exact name returns error") { + const std::string json = R"([ + {"name":"Agumon","id":"BO-115","set_name":["Series 1 Booster Pack"]} + ])"; + const auto out = DigiBattle99CardPreviewSource::parsePrintVariants( + json, "Series 1 Starter Set", "Agumon"); + CHECK(out.isErr()); + } +} + +TEST_SUITE("DigiBattle99CardPreviewSource::detectPrintVariants") { + TEST_CASE("round-trips through FixedHttpClient") { + FixedHttpClient http; + http.body = R"([ + {"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}, + {"name":"Agumon","id":"ST-126","set_name":["Series 1 Starter Set"]} + ])"; + DigiBattle99CardPreviewSource src{http}; + const auto out = src.detectPrintVariants("Agumon", "Series 1 Starter Set"); + REQUIRE(out.isOk()); + REQUIRE(out.value().size() == 2); + CHECK(out.value()[0].setNo == "ST-01"); + CHECK(out.value()[1].setNo == "ST-126"); + } +} diff --git a/tests/digibattle99_set_source_tests.cpp b/tests/digibattle99_set_source_tests.cpp new file mode 100644 index 0000000..831ddd3 --- /dev/null +++ b/tests/digibattle99_set_source_tests.cpp @@ -0,0 +1,112 @@ +#include + +#include "ccm/games/digibattle99/DigiBattle99SetSource.hpp" +#include "ccm/ports/IHttpClient.hpp" + +using namespace ccm; + +namespace { + +class FixedHttpClient final : public IHttpClient { +public: + std::string lastUrl; + std::string body; + bool ok = true; + Result get(std::string_view url) override { + lastUrl = std::string(url); + return ok ? Result::ok(body) + : Result::err("offline"); + } +}; + +} // namespace + +TEST_SUITE("DigiBattle99SetSource::slugifyPackName") { + TEST_CASE("slugifies pack display names") { + CHECK(DigiBattle99SetSource::slugifyPackName("Series 1 Starter Set") == + "series-1-starter-set"); + CHECK(DigiBattle99SetSource::slugifyPackName("Digimon The Movie Promo Cards") == + "digimon-the-movie-promo-cards"); + } +} + +TEST_SUITE("DigiBattle99SetSource::parseResponse") { + TEST_CASE("derives unique packs with curated release dates") { + const std::string json = R"([ + {"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}, + {"name":"MetalGreymon","id":"BO-01","set_name":["Series 1 Booster Pack"]}, + {"name":"Agumon","id":"ST-126","set_name":["Series 1 Starter Set"]}, + {"name":"Promo","id":"MO-06","set_name":["Digimon The Movie Promo Cards"]} + ])"; + + const auto out = DigiBattle99SetSource::parseResponse(json); + REQUIRE(out.isOk()); + REQUIRE(out.value().size() == 3); + // Same curated date for Series 1 products → secondary sort by name: + // "Booster" before "Starter". + CHECK(out.value()[0].id == "series-1-booster-pack"); + CHECK(out.value()[0].name == "Series 1 Booster Pack"); + CHECK(out.value()[0].releaseDate == "1999/06/01"); + CHECK(out.value()[1].id == "series-1-starter-set"); + CHECK(out.value()[1].name == "Series 1 Starter Set"); + CHECK(out.value()[1].releaseDate == "1999/06/01"); + CHECK(out.value()[2].id == "digimon-the-movie-promo-cards"); + CHECK(out.value()[2].releaseDate == "2000/10/01"); + } + + TEST_CASE("sorts by release date then name") { + const std::string json = R"([ + {"name":"A","id":"ST-1","set_name":["Street Starter Set 2"]}, + {"name":"B","id":"ST-2","set_name":["Series 1 Starter Set"]}, + {"name":"C","id":"ST-3","set_name":["Street Starter Set 1"]} + ])"; + const auto out = DigiBattle99SetSource::parseResponse(json); + REQUIRE(out.isOk()); + REQUIRE(out.value().size() == 3); + CHECK(out.value()[0].name == "Series 1 Starter Set"); + CHECK(out.value()[1].name == "Street Starter Set 1"); + CHECK(out.value()[2].name == "Street Starter Set 2"); + } + + TEST_CASE("empty array returns an empty list") { + const auto out = DigiBattle99SetSource::parseResponse("[]"); + REQUIRE(out.isOk()); + CHECK(out.value().empty()); + } + + TEST_CASE("non-array object with error is an error") { + const auto out = DigiBattle99SetSource::parseResponse( + R"({"error":"No cards found for this search."})"); + CHECK(out.isErr()); + } + + TEST_CASE("missing top-level array returns an error") { + const auto out = DigiBattle99SetSource::parseResponse(R"({"meta":{}})"); + CHECK(out.isErr()); + } + + TEST_CASE("invalid JSON returns an error") { + const auto out = DigiBattle99SetSource::parseResponse("{not json"); + CHECK(out.isErr()); + } +} + +TEST_SUITE("DigiBattle99SetSource::fetchAll") { + TEST_CASE("network error is surfaced as a Result error") { + FixedHttpClient http; + http.ok = false; + DigiBattle99SetSource src{http}; + CHECK(src.fetchAll().isErr()); + } + + TEST_CASE("network success hits the Digi-Battle search endpoint") { + FixedHttpClient http; + http.ok = true; + http.body = R"([{"name":"Agumon","id":"ST-01","set_name":["Series 1 Starter Set"]}])"; + DigiBattle99SetSource src{http}; + const auto out = src.fetchAll(); + REQUIRE(out.isOk()); + CHECK(out.value().front().id == "series-1-starter-set"); + CHECK(http.lastUrl == DigiBattle99SetSource::kEndpoint); + } +} diff --git a/tests/domain_json_tests.cpp b/tests/domain_json_tests.cpp index ec99884..fcd264f 100644 --- a/tests/domain_json_tests.cpp +++ b/tests/domain_json_tests.cpp @@ -1,6 +1,7 @@ #include #include "ccm/domain/Configuration.hpp" +#include "ccm/domain/DigiBattle99Card.hpp" #include "ccm/domain/Enums.hpp" #include "ccm/domain/MagicCard.hpp" #include "ccm/domain/PokemonCard.hpp" @@ -23,6 +24,9 @@ TEST_SUITE("domain enums round-trip JSON as strings") { nlohmann::json jYgo = "YuGiOh"; CHECK(jYgo.get() == Game::YuGiOh); + nlohmann::json jDigi = "DigiBattle99"; + CHECK(jDigi.get() == Game::DigiBattle99); + nlohmann::json j3 = Theme::Dark; CHECK(j3.get() == "Dark"); CHECK(j3.get() == Theme::Dark); @@ -153,6 +157,34 @@ TEST_SUITE("PokemonCard JSON") { } } +TEST_SUITE("DigiBattle99Card JSON") { + TEST_CASE("uses 'setNo' and 'firstEdition' aliases") { + DigiBattle99Card c; + c.id = 3; + c.amount = 2; + c.name = "Agumon"; + c.set = Set{"series-1-starter-set", "Series 1 Starter Set", "1999/06/01"}; + c.setNo = "ST-01"; + c.note = "starter"; + c.images = {"a.png"}; + c.language = Language::English; + c.condition = Condition::NearMint; + c.firstEdition = false; + c.holo = true; + c.signed_ = true; + c.altered = false; + + nlohmann::json j = c; + CHECK(j.at("setNo") == "ST-01"); + CHECK(j.at("firstEdition") == false); + CHECK(j.at("holo") == true); + CHECK(j.at("signed") == true); + + const DigiBattle99Card back = j.get(); + CHECK(back == c); + } +} + TEST_SUITE("Configuration JSON matches Rust serde aliases") { TEST_CASE("dataStorage / defaultGame / theme keys are present") { Configuration cfg; @@ -497,6 +529,36 @@ TEST_SUITE("Domain JSON required fields") { } } + TEST_CASE("DigiBattle99Card missing each required key throws") { + const nlohmann::json full = { + {"id", 3}, + {"amount", 1}, + {"name", "Agumon"}, + {"set", nlohmann::json{ + {"id", "series-1-starter-set"}, + {"name", "Series 1 Starter Set"}, + {"releaseDate", "1999/06/01"}, + }}, + {"setNo", "ST-01"}, + {"note", ""}, + {"images", nlohmann::json::array()}, + {"language", "English"}, + {"condition", "NearMint"}, + {"firstEdition", false}, + {"holo", true}, + {"signed", false}, + {"altered", false}, + }; + + for (const char* key : + {"id", "amount", "name", "set", "setNo", "note", "images", "language", "condition", + "firstEdition", "holo", "signed", "altered"}) { + nlohmann::json partial = full; + partial.erase(key); + CHECK_THROWS(partial.get()); + } + } + TEST_CASE("Configuration missing required key throws") { const nlohmann::json j = { {"defaultGame", "Magic"}, diff --git a/tests/game_module_tests.cpp b/tests/game_module_tests.cpp index a571206..607fe7e 100644 --- a/tests/game_module_tests.cpp +++ b/tests/game_module_tests.cpp @@ -1,5 +1,6 @@ #include +#include "ccm/games/digibattle99/DigiBattle99GameModule.hpp" #include "ccm/games/magic/MagicGameModule.hpp" #include "ccm/games/pokemon/PokemonGameModule.hpp" #include "ccm/games/yugioh/YuGiOhGameModule.hpp" @@ -51,4 +52,15 @@ TEST_SUITE("game modules expose stable identity and wiring") { CHECK(module.cardPreviewSource() != nullptr); CHECK(static_cast(&module.setSource()) != static_cast(module.cardPreviewSource())); } + + TEST_CASE("DigiBattle99 module reports canonical metadata") { + NoopHttpClient http; + DigiBattle99GameModule module(http); + + CHECK(module.id() == Game::DigiBattle99); + CHECK(module.dirName() == "digibattle99"); + CHECK(module.displayName() == "Digimon (Digi-Battle)"); + CHECK(module.cardPreviewSource() != nullptr); + CHECK(static_cast(&module.setSource()) != static_cast(module.cardPreviewSource())); + } } diff --git a/tests/local_image_store_tests.cpp b/tests/local_image_store_tests.cpp index 98b93ae..3c48fca 100644 --- a/tests/local_image_store_tests.cpp +++ b/tests/local_image_store_tests.cpp @@ -17,6 +17,7 @@ std::string dirNameForGame(Game g) { case Game::Magic: return "magic"; case Game::Pokemon: return "pokemon"; case Game::YuGiOh: return "yugioh"; + case Game::DigiBattle99: return "digibattle99"; } return "magic"; } diff --git a/tests/set_service_tests.cpp b/tests/set_service_tests.cpp index 26656af..7be748a 100644 --- a/tests/set_service_tests.cpp +++ b/tests/set_service_tests.cpp @@ -148,6 +148,37 @@ TEST_SUITE("SetService") { CHECK(yugioh.source.calls == 1); } + TEST_CASE("DigiBattle99 module routes independently when all games are registered") { + InMemSetRepo repo; + SetService svc{repo}; + + FakeGameModule magic{Game::Magic}; + magic.source.result = Result>::ok({{"lea", "Alpha", "1993/08/05"}}); + FakeGameModule pokemon{Game::Pokemon}; + pokemon.source.result = Result>::ok({{"base1", "Base", "1999/01/09"}}); + FakeGameModule yugioh{Game::YuGiOh}; + yugioh.source.result = Result>::ok({{"LOB", "Legend of Blue Eyes", "2002/03/08"}}); + FakeGameModule digi{Game::DigiBattle99}; + digi.source.result = Result>::ok( + {{"series-1-starter-set", "Series 1 Starter Set", "1999/06/01"}}); + + svc.registerModule(&magic); + svc.registerModule(&pokemon); + svc.registerModule(&yugioh); + svc.registerModule(&digi); + + REQUIRE(svc.updateSets(Game::Magic).isOk()); + REQUIRE(svc.updateSets(Game::Pokemon).isOk()); + REQUIRE(svc.updateSets(Game::YuGiOh).isOk()); + const auto out = svc.updateSets(Game::DigiBattle99); + REQUIRE(out.isOk()); + CHECK(out.value().front().id == "series-1-starter-set"); + CHECK(magic.source.calls == 1); + CHECK(pokemon.source.calls == 1); + CHECK(yugioh.source.calls == 1); + CHECK(digi.source.calls == 1); + } + TEST_CASE("updateSets propagates repository save failures") { InMemSetRepo repo; repo.failSave = true; diff --git a/ui_wx/AGENTS.md b/ui_wx/AGENTS.md index 0e2aa70..f6cc847 100644 --- a/ui_wx/AGENTS.md +++ b/ui_wx/AGENTS.md @@ -9,7 +9,7 @@ - `include/ccm/ui/MainFrame.hpp` + `src/MainFrame.cpp` — top-level window (default size `1210×770`), menu strip (`File` / `Game` / `Sets` / `Help`), toolbar (Add / Edit / Delete + filter input), and the splitter that swaps the active `IGameView`'s panels. The `Game` and `Sets` menus are built dynamically from `AppContext::gameViews` so adding a new game lights up its menu entries automatically. Filter and toolbar actions forward to `activeView()`. `EVT_PREVIEW_STATUS` (preview fetch outcome → status label; empty string resets to `"Ready"`) is the only event the frame binds; `EVT_CARD_SELECTED` is bound *per view* (each `IGameView` connects its typed list panel to its typed selected panel internally). About is a custom themed dialog (not `wxAboutBox`) so dark mode behavior stays consistent. - `include/ccm/ui/BaseCardListPanel.hpp` — header-only template `BaseCardListPanel` that owns ALL the non-game-specific `wxListCtrl` machinery: hidden zero-width spacer column (legacy of the MSW comctl32 image-list gutter workaround, kept to preserve column-index math), themed header row (clickable to sort, edge-drag to resize, divider double-click to autosize), per-icon-column cached `wxBitmap` pairs (normal + selected color) consumed by `IconListCtrl::MSWOnNotify` so row icons are pixel-perfect centered under the themed-header icons, rebuild guard so DESELECTED/SELECTED storms collapse into a single bubbled `EVT_CARD_SELECTED`, case-insensitive substring filter via `setFilter(...)`, per-column toggle-direction sort. Subclasses fill in column descriptors + per-row text + per-icon-column flag predicates + dispatch hooks (`sortBy`, `matchesFilter`). - `include/ccm/ui/IconListCtrl.hpp` + `src/IconListCtrl.cpp` — small `wxListCtrl` subclass that intercepts `NM_CUSTOMDRAW` on Windows and paints flag-icon sub-items at the exact center of each cell. It owns a `HIMAGELIST` (built from the cached `wxBitmap` pairs via straight-RGBA 32 bpp DIB sections) and draws each cell's icon with `ImageList_Draw(ILD_TRANSPARENT)` onto the native `HDC` from `NMLVCUSTOMDRAW`. This is the same low-level pixel path `wxImageList` uses internally, which is the only rendering path that has reliably preserved SVG transparency + correct fill color across light/dark themes on MSW. Two earlier attempts — `wxGraphicsContext::DrawBitmap` and a manually-premultiplied-DIB `AlphaBlend` — both rendered runtime-fill SVG icons as solid white in light mode and were abandoned (see convention 11). The custom-draw is purely about positioning; pixel format handling is delegated to comctl32. -- `include/ccm/ui/BaseSelectedCardPanel.hpp` — header-only template `BaseSelectedCardPanel` that owns the right-hand-side detail panel: preview image fetched via `CardPreviewService` (with the `shared_ptr` + `std::atomic alive`/`currentGen` cancellation pattern), 2-column detail grid, flag-icon strip that collapses when no flags are set, image list with double-click viewer. If preview lookup fails or returns empty bytes, the panel loads a per-game **card-back fallback**: Magic and Pokémon use fixed HTTPS URLs (`fallbackImageUrlForGame`, CCM2-aligned); **Yu-Gi-Oh!** tries Yugipedia thumbnail URL, then full `Back-EN.png` on `ms.yugipedia.com`, then reads `/assets/ygo_card_back.png` (copied next to the executable by `app/CMakeLists.txt` on link — source file `ui_wx/assets/ygo_card_back.png`). The constructor caches `/` for that disk path. Subclasses describe the detail rows / flag icons / preview lookup `(name, setId, setNo)` and own a `Game` constant. +- `include/ccm/ui/BaseSelectedCardPanel.hpp` — header-only template `BaseSelectedCardPanel` that owns the right-hand-side detail panel: preview image fetched via `CardPreviewService` (with the `shared_ptr` + `std::atomic alive`/`currentGen` cancellation pattern), 2-column detail grid, flag-icon strip that collapses when no flags are set, image list with double-click viewer. If preview lookup fails or returns empty bytes, the panel loads a per-game **card-back fallback**: Magic and Pokémon use fixed HTTPS URLs (`fallbackImageUrlForGame`, CCM2-aligned); **Yu-Gi-Oh!** tries Yugipedia thumbnail URL, then full `Back-EN.png` on `ms.yugipedia.com`, then reads `/assets/ygo_card_back.png`; **Digimon Digi-Battle** reads `/assets/digibattle99_card_back.png` (both bundled assets copied by `app/CMakeLists.txt` on link). The constructor caches `/` for that disk path. Subclasses describe the detail rows / flag icons / preview lookup `(name, setId, setNo)` and own a `Game` constant. - `include/ccm/ui/BaseCardEditDialog.hpp` — header-only template `BaseCardEditDialog` that owns the standard Add/Edit form: Name, Set picker (read-only `wxComboBox` with prefix-match typeahead and case-insensitive id matching for legacy data), Amount spin, Language and Condition choices, Note, image management (Add multiple via `wxFD_MULTIPLE`, Remove, double-click to view), OK/Cancel + validation. The **Set** row is built on a host `wxPanel` with a horizontal `wxBoxSizer`; games may override `customizeSetPickerRow(row, combo)` to wrap the combo (default: combo only). After a programmatic selection, `applySetSelectionByIndex` updates `card_.set` and calls `onSetSelectionApplied()` (default no-op). After `buildAndPopulate()`, the template snapshots the loaded card into `openingSnapshot_`; in **`EditMode::Edit`**, OK asks **Yes/No** (“Save changes to this card?”) only when the card differs from that snapshot (dirty-only confirm). **Create** mode never prompts. Subclasses build the flags row (`buildFlagsRow`), append game-specific extra rows (e.g. Pokemon's `Set #`) via `appendExtraRows`, and copy values in/out of the typed card (`readExtraFromCard` / `writeExtraToCard`). The template binds `EVT_TEXT` on **Name** and invokes `onCardLookupContextChanged()` so games can drop stale keyed metadata when the user edits the lookup identity (Yu-Gi-Oh! clears its YGOPRODeck print-variant cache here). `YuGiOhCardEditDialog` overrides `customizeSetPickerRow` to add a **`SwitchCtrl`** pill switch plus a **hint** label (`Set name` / `Set code`), a text field, and **Auto detect** (resolves `Set.id` via `ccm/util/YuGiOhSetLookup.hpp` against `availableSets()`, then returns to the dropdown on success); it overrides `onSetSelectionApplied` to match manual set-change behavior. It additionally `CallAfter`s a silent `detectPrintVariants` when opening **Edit** (and after changing **Set**) so multi-print **Next** buttons can appear without pressing Auto detect first, as long as name + display set are populated. The base also exposes helpers to sync current control values and inspect the currently-selected set when a subclass needs derived-field UI. - `include/ccm/ui/SwitchCtrl.hpp` + `src/SwitchCtrl.cpp` — custom pill-track + thumb switch for small modal rows (Yu-Gi-Oh! set picker); fires `EVT_CCM_SWITCH` on user toggle and reads colors from `inferThemeFromWindow` / `paletteForTheme`. - `include/ccm/ui/Magic*.hpp` + `src/Magic*.cpp` — Magic implementations: `MagicCardListPanel`, `MagicSelectedCardPanel`, `MagicCardEditDialog`, `MagicGameView`. Each is ~50–100 lines of hook overrides on top of the matching base template. @@ -67,7 +67,7 @@ - When validating UI theming changes, rebuild and run `ccm` (the executable), not just `ccm_ui_wx`. 15. **Preview fallback behavior (CCM2 parity where applicable):** - Keep unresolved external previews user-visible by showing a per-game card-back image in `BaseSelectedCardPanel` instead of a blank/transparent bitmap. - - Magic / Pokémon use single fixed HTTPS URLs (`Magic_card_back.jpg`, Bulbagarden `Cardback.jpg`). Yu-Gi-Oh! uses Yugipedia-hosted backs plus a **bundled** PNG beside the exe (`assets/ygo_card_back.png`) when the network path fails — keep that chain working when touching preview code. + - Magic / Pokémon use single fixed HTTPS URLs (`Magic_card_back.jpg`, Bulbagarden `Cardback.jpg`). Yu-Gi-Oh! uses Yugipedia-hosted backs plus a **bundled** PNG beside the exe (`assets/ygo_card_back.png`) when the network path fails. Digimon Digi-Battle uses a **bundled** PNG (`assets/digibattle99_card_back.png`) — keep those chains working when touching preview code. - If you change fallback sourcing (URLs or bundled asset), keep the "always show a reasonable card-back fallback" behavior intact for **every** game with remote previews. 16. **Per-game auto-detect controls:** - Auto-detect actions in edit dialogs (e.g. detect set print number / rarity from API) are opt-in per game. @@ -76,7 +76,7 @@ ## Required follow-ups -- If you replace **`ui_wx/assets/ygo_card_back.png`**, rebuild the **`ccm`** target so `app/CMakeLists.txt`'s `POST_BUILD` copy refreshes `/assets/`; do not remove the asset without updating `BaseSelectedCardPanel` / `docs/assets-and-info-apis.md`. +- If you replace **`ui_wx/assets/ygo_card_back.png`** or **`ui_wx/assets/digibattle99_card_back.png`**, rebuild the **`ccm`** target so `app/CMakeLists.txt`'s `POST_BUILD` copy refreshes `/assets/`; do not remove an asset without updating `BaseSelectedCardPanel` / `docs/assets-and-info-apis.md`. - After adding a new dialog/panel `.cpp` you **must** add it to `ui_wx/CMakeLists.txt`. - After adding a new menu action you **must** allocate an `Ids::*` value in `MainFrame.hpp` (don't reuse `wxID_HIGHEST` math inline) and `Bind` it in `buildMenuBar`. The dynamic Game / Sets menus consume the `IdGameMenuBase` / `IdSetsMenuBase` ranges; do not stomp on those id ranges. - After changing `AppContext` you **must** update `app/main.cpp` so the composition root populates the new field. diff --git a/ui_wx/CMakeLists.txt b/ui_wx/CMakeLists.txt index b8dbf09..5bb90b5 100644 --- a/ui_wx/CMakeLists.txt +++ b/ui_wx/CMakeLists.txt @@ -19,6 +19,10 @@ add_library(ccm_ui_wx STATIC src/YuGiOhSelectedCardPanel.cpp src/YuGiOhCardEditDialog.cpp src/YuGiOhGameView.cpp + src/DigiBattle99CardListPanel.cpp + src/DigiBattle99SelectedCardPanel.cpp + src/DigiBattle99CardEditDialog.cpp + src/DigiBattle99GameView.cpp src/SettingsDialog.cpp src/SwitchCtrl.cpp diff --git a/ui_wx/assets/digibattle99_card_back.png b/ui_wx/assets/digibattle99_card_back.png new file mode 100644 index 0000000000000000000000000000000000000000..e6a3d202e26dc4e18a0bcac3a72cd3c3e3f8eda2 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^4nUm1!2~3gmOtJPq|!ZI978H@y*=;9$-uzDvf*^1 ri1Msk`*~Xqa_LgTe~DWM4fYrq`A literal 0 HcmV?d00001 diff --git a/ui_wx/include/ccm/ui/AppContext.hpp b/ui_wx/include/ccm/ui/AppContext.hpp index 3bfd551..be020c4 100644 --- a/ui_wx/include/ccm/ui/AppContext.hpp +++ b/ui_wx/include/ccm/ui/AppContext.hpp @@ -26,6 +26,7 @@ struct AppContext { IGameModule& magicModule; IGameModule& pokemonModule; IGameModule& yuGiOhModule; + IGameModule& digiBattle99Module; // Active per-game UI bundles. The order is the order shown in the // Game menu; the composition root constructs them and hands raw // pointers in. `MainFrame` does not own these — `app/main.cpp` does. diff --git a/ui_wx/include/ccm/ui/BaseSelectedCardPanel.hpp b/ui_wx/include/ccm/ui/BaseSelectedCardPanel.hpp index eaf5eb2..5c6043c 100644 --- a/ui_wx/include/ccm/ui/BaseSelectedCardPanel.hpp +++ b/ui_wx/include/ccm/ui/BaseSelectedCardPanel.hpp @@ -295,9 +295,11 @@ private: case Game::YuGiOh: // Yugipedia English TCG backing (thumbnail — smaller than full scan). return "https://ms.yugipedia.com/thumb/e/e5/Back-EN.png/250px-Back-EN.png"; - default: + case Game::DigiBattle99: + // No stable public Digi-Battle back URL; UI uses bundled PNG. return {}; } + return {}; } void buildInfoGrid(wxBoxSizer* root) { @@ -424,6 +426,16 @@ private: applyFallbackPayload(ss.str()); } } + } else if (game == Game::DigiBattle99) { + namespace fs = std::filesystem; + const fs::path asset = + fs::path(exeDirCopy) / "assets" / "digibattle99_card_back.png"; + std::ifstream in(asset, std::ios::binary); + if (in) { + std::ostringstream ss; + ss << in.rdbuf(); + applyFallbackPayload(ss.str()); + } } else { const std::string fallbackUrl = fallbackImageUrlForGame(game); if (!fallbackUrl.empty()) { diff --git a/ui_wx/include/ccm/ui/DigiBattle99CardEditDialog.hpp b/ui_wx/include/ccm/ui/DigiBattle99CardEditDialog.hpp new file mode 100644 index 0000000..82f0d8f --- /dev/null +++ b/ui_wx/include/ccm/ui/DigiBattle99CardEditDialog.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include "ccm/domain/DigiBattle99Card.hpp" +#include "ccm/ports/ICardPreviewSource.hpp" +#include "ccm/services/CardPreviewService.hpp" +#include "ccm/ui/BaseCardEditDialog.hpp" +#include + +#include +#include +#include +#include + +namespace ccm::ui { + +class DigiBattle99CardEditDialog final : public BaseCardEditDialog { +public: + DigiBattle99CardEditDialog(wxWindow* parent, + ImageService& imageService, + SetService& setService, + CardPreviewService& cardPreview, + EditMode mode, + DigiBattle99Card initial, + const std::vector* preloadedSets = nullptr); + ~DigiBattle99CardEditDialog() override; + +protected: + void buildFlagsRow(wxBoxSizer* flagsBox) override; + void appendExtraRows(wxFlexGridSizer* grid) override; + void readExtraFromCard() override; + void writeExtraToCard() override; + [[nodiscard]] std::string updateMenuName() const override { + return "Update Digimon (Digi-Battle)"; + } + void onCardLookupContextChanged() override; + +private: + struct VariantFetchState { + std::atomic alive{true}; + }; + + void onAutoDetectSetNo(wxCommandEvent&); + void onNextSetNo(wxCommandEvent&); + void onSetSelectionChanged(wxCommandEvent&); + void autoDetectFromApi(); + void clearCachedPrintVariants(); + void requestVariantsAsync(unsigned capturedEpoch, + std::string name, + std::string setName, + bool fillSetNoOnSuccess, + bool showFailureDialog); + void applyDetectedVariants(unsigned capturedEpoch, + Result> detected, + bool fillSetNoOnSuccess, + bool showFailureDialog); + void rebuildVariantRingFromCache(); + void syncRingPositionToControls(); + void refreshVariantNextControls(); + void scheduleDeferredVariantPrefetch(); + void prefetchVariantsForCurrentCardSilent(unsigned capturedEpoch); + [[nodiscard]] static std::string storedSetNoFromControls(const wxTextCtrl* ctrl); + [[nodiscard]] static std::string normalizedStoredSetNo(std::string_view setNo); + + EditMode dialogMode_; + unsigned variantFetchEpoch_{0}; + CardPreviewService& cardPreview_; + std::shared_ptr variantFetchState_; + wxTextCtrl* setNoCtrl_{nullptr}; + wxButton* autoSetNoBtn_{nullptr}; + wxButton* nextSetNoBtn_{nullptr}; + wxCheckBox* holoCheck_{nullptr}; + wxCheckBox* firstEditionCheck_{nullptr}; + wxCheckBox* signedCheck_{nullptr}; + wxCheckBox* alteredCheck_{nullptr}; + + std::vector cachedVariants_; + std::vector uniqueSetNos_; + std::size_t setNoRingPos_{0}; +}; + +} // namespace ccm::ui diff --git a/ui_wx/include/ccm/ui/DigiBattle99CardListPanel.hpp b/ui_wx/include/ccm/ui/DigiBattle99CardListPanel.hpp new file mode 100644 index 0000000..88ca286 --- /dev/null +++ b/ui_wx/include/ccm/ui/DigiBattle99CardListPanel.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "ccm/domain/DigiBattle99Card.hpp" +#include "ccm/services/CardSorter.hpp" +#include "ccm/ui/BaseCardListPanel.hpp" + +namespace ccm::ui { + +class DigiBattle99CardListPanel final + : public BaseCardListPanel { +public: + explicit DigiBattle99CardListPanel(wxWindow* parent); + +protected: + [[nodiscard]] std::vector declareTextColumns() const override; + [[nodiscard]] std::vector declareIconColumns() const override; + [[nodiscard]] std::string renderTextCell(const DigiBattle99Card& card, + std::size_t idx) const override; + [[nodiscard]] bool isIconColumnSet(const DigiBattle99Card& card, + std::size_t idx) const override; + void sortBy(DigiBattle99SortColumn column, bool ascending) override; + [[nodiscard]] bool matchesFilter(const DigiBattle99Card& card, + std::string_view filter) const override; +}; + +} // namespace ccm::ui diff --git a/ui_wx/include/ccm/ui/DigiBattle99GameView.hpp b/ui_wx/include/ccm/ui/DigiBattle99GameView.hpp new file mode 100644 index 0000000..bc31c47 --- /dev/null +++ b/ui_wx/include/ccm/ui/DigiBattle99GameView.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "ccm/domain/DigiBattle99Card.hpp" +#include "ccm/games/IGameModule.hpp" +#include "ccm/services/CardPreviewService.hpp" +#include "ccm/services/CollectionService.hpp" +#include "ccm/services/ConfigService.hpp" +#include "ccm/services/ImageService.hpp" +#include "ccm/services/SetService.hpp" +#include "ccm/ui/IGameView.hpp" + +#include +#include +#include + +namespace ccm::ui { + +class DigiBattle99CardListPanel; +class DigiBattle99SelectedCardPanel; + +class DigiBattle99GameView final : public IGameView { +public: + DigiBattle99GameView(ConfigService& config, + CollectionService& collection, + SetService& sets, + ImageService& images, + CardPreviewService& cardPreview, + IGameModule& module); + + [[nodiscard]] Game gameId() const noexcept override { return Game::DigiBattle99; } + [[nodiscard]] std::string displayName() const override { return "Digimon (Digi-Battle)"; } + + wxPanel* listPanel(wxWindow* parent) override; + wxPanel* selectedPanel(wxWindow* parent) override; + + void refreshCollection() override; + void onAddCard(wxWindow* parentWindow) override; + void onEditCard(wxWindow* parentWindow) override; + void onDeleteCard(wxWindow* parentWindow) override; + std::string onUpdateSets(wxWindow* parentWindow) override; + void setFilter(std::string_view filter) override; + void applyTheme(const ThemePalette& palette) override; + [[nodiscard]] std::string updateSetsMenuLabel() const override { + return "Update Digimon (Digi-Battle)"; + } + +private: + void ensureSetsLoaded(); + const std::vector& setsForDialog(); + + ConfigService& config_; + CollectionService& collection_; + SetService& sets_; + ImageService& images_; + CardPreviewService& cardPreview_; + IGameModule& module_; + + DigiBattle99CardListPanel* listPanel_{nullptr}; + DigiBattle99SelectedCardPanel* selectedPanel_{nullptr}; + std::vector setsCache_; + bool attemptedInitialSetLoad_{false}; +}; + +} // namespace ccm::ui diff --git a/ui_wx/include/ccm/ui/DigiBattle99SelectedCardPanel.hpp b/ui_wx/include/ccm/ui/DigiBattle99SelectedCardPanel.hpp new file mode 100644 index 0000000..378e262 --- /dev/null +++ b/ui_wx/include/ccm/ui/DigiBattle99SelectedCardPanel.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "ccm/domain/DigiBattle99Card.hpp" +#include "ccm/ui/BaseSelectedCardPanel.hpp" + +namespace ccm::ui { + +class DigiBattle99SelectedCardPanel final : public BaseSelectedCardPanel { +public: + DigiBattle99SelectedCardPanel(wxWindow* parent, + ImageService& imageService, + CardPreviewService& cardPreview); + +protected: + [[nodiscard]] std::vector declareDetailRows() const override; + [[nodiscard]] std::vector declareFlagIcons() const override; + [[nodiscard]] std::string detailValueFor(const DigiBattle99Card& card, + DetailKey key) const override; + [[nodiscard]] bool isFlagSet(const DigiBattle99Card& card, DetailKey key) const override; + [[nodiscard]] std::tuple + previewKey(const DigiBattle99Card& card) const override; + [[nodiscard]] Game gameId() const noexcept override { return Game::DigiBattle99; } +}; + +} // namespace ccm::ui diff --git a/ui_wx/src/DigiBattle99CardEditDialog.cpp b/ui_wx/src/DigiBattle99CardEditDialog.cpp new file mode 100644 index 0000000..17d7683 --- /dev/null +++ b/ui_wx/src/DigiBattle99CardEditDialog.cpp @@ -0,0 +1,255 @@ +#include "ccm/ui/DigiBattle99CardEditDialog.hpp" + +#include "ccm/domain/Enums.hpp" +#include "ccm/games/digibattle99/DigiBattle99CardPreviewSource.hpp" +#include +#include +#include +#include + +namespace ccm::ui { + +DigiBattle99CardEditDialog::DigiBattle99CardEditDialog(wxWindow* parent, + ImageService& imageService, + SetService& setService, + CardPreviewService& cardPreview, + EditMode mode, + DigiBattle99Card initial, + const std::vector* preloadedSets) + : BaseCardEditDialog( + parent, + mode == EditMode::Create ? "Add Digimon (Digi-Battle) Card" + : "Edit Digimon (Digi-Battle) Card", + imageService, setService, mode, std::move(initial), Game::DigiBattle99, + preloadedSets), + dialogMode_(mode), + cardPreview_(cardPreview), + variantFetchState_(std::make_shared()) { + buildAndPopulate(); + if (dialogMode_ == EditMode::Edit) { + scheduleDeferredVariantPrefetch(); + } +} + +DigiBattle99CardEditDialog::~DigiBattle99CardEditDialog() { + if (variantFetchState_) { + variantFetchState_->alive.store(false); + } +} + +void DigiBattle99CardEditDialog::onCardLookupContextChanged() { + clearCachedPrintVariants(); +} + +void DigiBattle99CardEditDialog::buildFlagsRow(wxBoxSizer* flagsBox) { + holoCheck_ = new wxCheckBox(this, wxID_ANY, "Holo"); + firstEditionCheck_ = new wxCheckBox(this, wxID_ANY, "1. Edition"); + signedCheck_ = new wxCheckBox(this, wxID_ANY, "Signed"); + alteredCheck_ = new wxCheckBox(this, wxID_ANY, "Altered"); + flagsBox->Add(holoCheck_, 0, wxRIGHT, 12); + flagsBox->Add(firstEditionCheck_, 0, wxRIGHT, 12); + flagsBox->Add(signedCheck_, 0, wxRIGHT, 12); + flagsBox->Add(alteredCheck_, 0, wxRIGHT, 12); +} + +void DigiBattle99CardEditDialog::appendExtraRows(wxFlexGridSizer* grid) { + auto* setNoPanel = new wxPanel(this, wxID_ANY); + setNoCtrl_ = new wxTextCtrl(setNoPanel, wxID_ANY); + autoSetNoBtn_ = new wxButton(setNoPanel, wxID_ANY, "Auto detect"); + autoSetNoBtn_->Bind(wxEVT_BUTTON, &DigiBattle99CardEditDialog::onAutoDetectSetNo, this); + nextSetNoBtn_ = new wxButton(setNoPanel, wxID_ANY, "Next"); + nextSetNoBtn_->Bind(wxEVT_BUTTON, &DigiBattle99CardEditDialog::onNextSetNo, this); + nextSetNoBtn_->Show(false); + auto* setNoRow = new wxBoxSizer(wxHORIZONTAL); + setNoRow->Add(setNoCtrl_, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 6); + setNoRow->Add(autoSetNoBtn_, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 6); + setNoRow->Add(nextSetNoBtn_, 0, wxALIGN_CENTER_VERTICAL); + setNoPanel->SetSizer(setNoRow); + + appendRow(grid, "Set #", setNoPanel); + + if (auto* setCombo = setComboControl()) { + setCombo->Bind(wxEVT_COMBOBOX, &DigiBattle99CardEditDialog::onSetSelectionChanged, this); + } +} + +std::string DigiBattle99CardEditDialog::normalizedStoredSetNo(std::string_view setNo) { + return DigiBattle99CardPreviewSource::normalizeCardNumber(setNo); +} + +std::string DigiBattle99CardEditDialog::storedSetNoFromControls(const wxTextCtrl* ctrl) { + if (ctrl == nullptr) return {}; + return normalizedStoredSetNo(ctrl->GetValue().ToStdString(wxConvUTF8)); +} + +void DigiBattle99CardEditDialog::readExtraFromCard() { + clearCachedPrintVariants(); + if (setNoCtrl_) { + setNoCtrl_->ChangeValue( + wxString::FromUTF8(normalizedStoredSetNo(constCard().setNo).c_str())); + } + if (holoCheck_) holoCheck_->SetValue(constCard().holo); + if (firstEditionCheck_) firstEditionCheck_->SetValue(constCard().firstEdition); + if (signedCheck_) signedCheck_->SetValue(constCard().signed_); + if (alteredCheck_) alteredCheck_->SetValue(constCard().altered); +} + +void DigiBattle99CardEditDialog::writeExtraToCard() { + if (setNoCtrl_) mutableCard().setNo = storedSetNoFromControls(setNoCtrl_); + if (holoCheck_) mutableCard().holo = holoCheck_->IsChecked(); + if (firstEditionCheck_) mutableCard().firstEdition = firstEditionCheck_->IsChecked(); + if (signedCheck_) mutableCard().signed_ = signedCheck_->IsChecked(); + if (alteredCheck_) mutableCard().altered = alteredCheck_->IsChecked(); +} + +void DigiBattle99CardEditDialog::clearCachedPrintVariants() { + ++variantFetchEpoch_; + cachedVariants_.clear(); + uniqueSetNos_.clear(); + setNoRingPos_ = 0; + refreshVariantNextControls(); +} + +void DigiBattle99CardEditDialog::scheduleDeferredVariantPrefetch() { + const unsigned epoch = variantFetchEpoch_; + wxTheApp->CallAfter([this, epoch]() { + prefetchVariantsForCurrentCardSilent(epoch); + }); +} + +void DigiBattle99CardEditDialog::prefetchVariantsForCurrentCardSilent(unsigned capturedEpoch) { + if (capturedEpoch != variantFetchEpoch_) return; + if (!cachedVariants_.empty()) return; + const auto& card = constCard(); + // digimoncard.io pack= uses the display set name, not the slug id. + if (card.name.empty() || card.set.name.empty()) return; + + requestVariantsAsync(capturedEpoch, card.name, card.set.name, false, false); +} + +void DigiBattle99CardEditDialog::requestVariantsAsync(unsigned capturedEpoch, + std::string name, + std::string setName, + bool fillSetNoOnSuccess, + bool showFailureDialog) { + if (capturedEpoch != variantFetchEpoch_) return; + + if (fillSetNoOnSuccess && autoSetNoBtn_) { + autoSetNoBtn_->Disable(); + } + + auto state = variantFetchState_; + CardPreviewService* svc = &cardPreview_; + DigiBattle99CardEditDialog* self = this; + std::thread([state, svc, self, capturedEpoch, name = std::move(name), + setName = std::move(setName), fillSetNoOnSuccess, showFailureDialog]() { + auto detected = svc->detectPrintVariants(Game::DigiBattle99, name, setName); + wxTheApp->CallAfter([state, self, capturedEpoch, detected = std::move(detected), + fillSetNoOnSuccess, showFailureDialog]() mutable { + if (!state->alive.load()) return; + self->applyDetectedVariants(capturedEpoch, std::move(detected), + fillSetNoOnSuccess, showFailureDialog); + }); + }).detach(); +} + +void DigiBattle99CardEditDialog::applyDetectedVariants( + unsigned capturedEpoch, + Result> detected, + bool fillSetNoOnSuccess, + bool showFailureDialog) { + if (capturedEpoch != variantFetchEpoch_) return; + + if (fillSetNoOnSuccess && autoSetNoBtn_) { + autoSetNoBtn_->Enable(); + } + + if (!detected) { + if (showFailureDialog) { + showThemedMessageDialog(this, "Auto detect failed: " + detected.error(), "Auto detect", + wxOK | wxICON_WARNING); + } + return; + } + + cachedVariants_ = std::move(detected).value(); + if (fillSetNoOnSuccess && setNoCtrl_ && !cachedVariants_.empty()) { + setNoCtrl_->ChangeValue( + wxString::FromUTF8(cachedVariants_.front().setNo.c_str())); + } + + rebuildVariantRingFromCache(); + syncRingPositionToControls(); + refreshVariantNextControls(); +} + +void DigiBattle99CardEditDialog::rebuildVariantRingFromCache() { + uniqueSetNos_.clear(); + if (cachedVariants_.empty()) return; + + std::unordered_set seen; + seen.reserve(cachedVariants_.size()); + for (const auto& p : cachedVariants_) { + if (p.setNo.empty()) continue; + if (!seen.insert(p.setNo).second) continue; + uniqueSetNos_.push_back(p.setNo); + } +} + +void DigiBattle99CardEditDialog::syncRingPositionToControls() { + if (!setNoCtrl_) return; + const std::string current = storedSetNoFromControls(setNoCtrl_); + setNoRingPos_ = 0; + for (std::size_t i = 0; i < uniqueSetNos_.size(); ++i) { + if (uniqueSetNos_[i] == current) { + setNoRingPos_ = i; + break; + } + } +} + +void DigiBattle99CardEditDialog::refreshVariantNextControls() { + if (!nextSetNoBtn_) return; + nextSetNoBtn_->Show(uniqueSetNos_.size() > 1); + Layout(); + if (GetSizer()) Fit(); +} + +void DigiBattle99CardEditDialog::onAutoDetectSetNo(wxCommandEvent&) { + autoDetectFromApi(); +} + +void DigiBattle99CardEditDialog::onNextSetNo(wxCommandEvent&) { + if (uniqueSetNos_.size() <= 1) return; + setNoRingPos_ = (setNoRingPos_ + 1) % uniqueSetNos_.size(); + if (setNoCtrl_) { + setNoCtrl_->ChangeValue(wxString::FromUTF8(uniqueSetNos_[setNoRingPos_].c_str())); + } + refreshVariantNextControls(); +} + +void DigiBattle99CardEditDialog::autoDetectFromApi() { + syncCardFromControls(); + const auto& card = constCard(); + if (card.name.empty()) { + showThemedMessageDialog(this, "Enter a card name first.", "Auto detect", + wxOK | wxICON_INFORMATION); + return; + } + if (card.set.name.empty()) { + showThemedMessageDialog(this, "Select a set first.", "Auto detect", + wxOK | wxICON_INFORMATION); + return; + } + + const unsigned epoch = variantFetchEpoch_; + requestVariantsAsync(epoch, card.name, card.set.name, true, true); +} + +void DigiBattle99CardEditDialog::onSetSelectionChanged(wxCommandEvent& ev) { + clearCachedPrintVariants(); + scheduleDeferredVariantPrefetch(); + ev.Skip(); +} + +} // namespace ccm::ui diff --git a/ui_wx/src/DigiBattle99CardListPanel.cpp b/ui_wx/src/DigiBattle99CardListPanel.cpp new file mode 100644 index 0000000..c48813c --- /dev/null +++ b/ui_wx/src/DigiBattle99CardListPanel.cpp @@ -0,0 +1,71 @@ +#include "ccm/ui/DigiBattle99CardListPanel.hpp" + +#include "ccm/services/CardFilter.hpp" +#include "ccm/ui/SvgIcons.hpp" + +#include + +namespace ccm::ui { + +DigiBattle99CardListPanel::DigiBattle99CardListPanel(wxWindow* parent) + : BaseCardListPanel(parent) { + buildLayout(); +} + +std::vector +DigiBattle99CardListPanel::declareTextColumns() const { + return { + {"Name", 220, wxLIST_FORMAT_LEFT, DigiBattle99SortColumn::Name}, + {"Set", 180, wxLIST_FORMAT_LEFT, DigiBattle99SortColumn::SetReleaseDate}, + {"Amount", 70, wxLIST_FORMAT_RIGHT, DigiBattle99SortColumn::Amount}, + {"Condition", 100, wxLIST_FORMAT_LEFT, DigiBattle99SortColumn::Condition}, + {"Language", 100, wxLIST_FORMAT_LEFT, DigiBattle99SortColumn::Language}, + {"Note", 220, wxLIST_FORMAT_LEFT, DigiBattle99SortColumn::Note}, + }; +} + +std::vector +DigiBattle99CardListPanel::declareIconColumns() const { + constexpr int kFlagColWidth = 36; + return { + {kSvgHolo, kFlagColWidth, DigiBattle99SortColumn::Holo}, + {kSvgFirstEdition, kFlagColWidth, DigiBattle99SortColumn::FirstEdition}, + {kSvgSigned, kFlagColWidth, DigiBattle99SortColumn::Signed}, + {kSvgAltered, kFlagColWidth, DigiBattle99SortColumn::Altered}, + }; +} + +std::string DigiBattle99CardListPanel::renderTextCell(const DigiBattle99Card& card, + std::size_t idx) const { + switch (idx) { + case 0: return card.name; + case 1: return card.set.name; + case 2: return std::to_string(card.amount); + case 3: return std::string(to_string(card.condition)); + case 4: return std::string(to_string(card.language)); + case 5: return card.note; + } + return {}; +} + +bool DigiBattle99CardListPanel::isIconColumnSet(const DigiBattle99Card& card, + std::size_t idx) const { + switch (idx) { + case 0: return card.holo; + case 1: return card.firstEdition; + case 2: return card.signed_; + case 3: return card.altered; + } + return false; +} + +void DigiBattle99CardListPanel::sortBy(DigiBattle99SortColumn column, bool ascending) { + sortDigiBattle99Cards(mutableCards(), column, ascending); +} + +bool DigiBattle99CardListPanel::matchesFilter(const DigiBattle99Card& card, + std::string_view filter) const { + return matchesDigiBattle99Filter(card, filter); +} + +} // namespace ccm::ui diff --git a/ui_wx/src/DigiBattle99GameView.cpp b/ui_wx/src/DigiBattle99GameView.cpp new file mode 100644 index 0000000..f572074 --- /dev/null +++ b/ui_wx/src/DigiBattle99GameView.cpp @@ -0,0 +1,216 @@ +#include "ccm/ui/DigiBattle99GameView.hpp" + +#include "ccm/ui/CardEditModalGuard.hpp" +#include "ccm/ui/DigiBattle99CardEditDialog.hpp" +#include "ccm/ui/DigiBattle99CardListPanel.hpp" +#include "ccm/ui/DigiBattle99SelectedCardPanel.hpp" +#include "ccm/ui/Theme.hpp" + +#include +#include + +#include +#include + +namespace ccm::ui { + +DigiBattle99GameView::DigiBattle99GameView(ConfigService& config, + CollectionService& collection, + SetService& sets, + ImageService& images, + CardPreviewService& cardPreview, + IGameModule& module) + : config_(config), + collection_(collection), + sets_(sets), + images_(images), + cardPreview_(cardPreview), + module_(module) {} + +void DigiBattle99GameView::ensureSetsLoaded() { + if (attemptedInitialSetLoad_) return; + attemptedInitialSetLoad_ = true; + + auto cached = sets_.getSets(Game::DigiBattle99); + if (cached) { + setsCache_ = std::move(cached).value(); + if (!setsCache_.empty()) return; + } else { + setsCache_.clear(); + } + + auto refreshed = sets_.updateSets(Game::DigiBattle99); + if (refreshed) { + setsCache_ = std::move(refreshed).value(); + } +} + +wxPanel* DigiBattle99GameView::listPanel(wxWindow* parent) { + if (listPanel_ == nullptr) { + listPanel_ = new DigiBattle99CardListPanel(parent); + listPanel_->Bind(EVT_CARD_SELECTED, [this](wxCommandEvent&) { + if (selectedPanel_ != nullptr && listPanel_ != nullptr) { + selectedPanel_->setCard(listPanel_->selected()); + } + }); + listPanel_->Bind(EVT_CARD_ACTIVATED, [this](wxCommandEvent&) { + wxWindow* owner = wxGetTopLevelParent(listPanel_); + onEditCard(owner != nullptr ? owner : static_cast(listPanel_)); + }); + } + return listPanel_; +} + +wxPanel* DigiBattle99GameView::selectedPanel(wxWindow* parent) { + if (selectedPanel_ == nullptr) { + selectedPanel_ = new DigiBattle99SelectedCardPanel(parent, images_, cardPreview_); + } + return selectedPanel_; +} + +void DigiBattle99GameView::refreshCollection() { + if (listPanel_ == nullptr) return; + auto loaded = collection_.list(Game::DigiBattle99); + if (!loaded) { + showThemedMessageDialog( + nullptr, + "Failed to load Digimon (Digi-Battle) collection: " + loaded.error(), + "Error", wxOK | wxICON_ERROR); + return; + } + listPanel_->setCards(std::move(loaded).value()); + listPanel_->activateSelection(); + if (selectedPanel_) selectedPanel_->setCard(listPanel_->selected()); +} + +const std::vector& DigiBattle99GameView::setsForDialog() { + ensureSetsLoaded(); + if (!setsCache_.empty()) return setsCache_; + auto loaded = sets_.getSets(Game::DigiBattle99); + if (loaded) setsCache_ = std::move(loaded).value(); + else setsCache_.clear(); + return setsCache_; +} + +void DigiBattle99GameView::onAddCard(wxWindow* parentWindow) { + if (cardEditModalIsActive()) { + showThemedMessageDialog(parentWindow, wxString::FromUTF8(kCardEditModalBlockedUtf8), + wxString::FromUTF8("Add card"), wxOK | wxICON_INFORMATION); + return; + } + DigiBattle99Card fresh; + fresh.amount = 1; + fresh.language = Language::English; + fresh.condition = Condition::NearMint; + + DigiBattle99CardEditDialog dlg(parentWindow, images_, sets_, cardPreview_, EditMode::Create, + fresh, &setsForDialog()); + themeModalDialog(&dlg, config_.current().theme); + CardEditModalGuard modalGuard; + if (dlg.ShowModal() != wxID_OK) return; + + auto added = collection_.add(Game::DigiBattle99, dlg.card()); + if (!added) { + showThemedMessageDialog(parentWindow, "Failed to add card: " + added.error(), + "Error", wxOK | wxICON_ERROR); + return; + } + + DigiBattle99Card persisted = dlg.card(); + persisted.id = added.value(); + auto normalized = images_.normalizeNamesForPersistedCard( + Game::DigiBattle99, persisted.id, persisted.set.name, persisted.name, persisted.images); + if (normalized) { + if (normalized.value() != persisted.images) { + persisted.images = std::move(normalized).value(); + auto updated = collection_.update(Game::DigiBattle99, persisted); + if (!updated) { + showThemedMessageDialog( + parentWindow, + "Card added, but image name normalization failed to persist: " + + updated.error(), + "Warning", wxOK | wxICON_WARNING); + } + } + } else { + showThemedMessageDialog( + parentWindow, + "Card added, but image rename to ID-prefixed format failed: " + normalized.error(), + "Warning", wxOK | wxICON_WARNING); + } + refreshCollection(); +} + +void DigiBattle99GameView::onEditCard(wxWindow* parentWindow) { + if (listPanel_ == nullptr) return; + auto sel = listPanel_->selected(); + if (!sel) { + showThemedMessageDialog(parentWindow, "Select a card first.", "Edit", + wxOK | wxICON_INFORMATION); + return; + } + if (cardEditModalIsActive()) { + showThemedMessageDialog(parentWindow, wxString::FromUTF8(kCardEditModalBlockedUtf8), + wxString::FromUTF8("Edit"), wxOK | wxICON_INFORMATION); + return; + } + DigiBattle99CardEditDialog dlg(parentWindow, images_, sets_, cardPreview_, EditMode::Edit, + *sel, &setsForDialog()); + themeModalDialog(&dlg, config_.current().theme); + CardEditModalGuard modalGuard; + if (dlg.ShowModal() != wxID_OK) return; + auto updated = collection_.update(Game::DigiBattle99, dlg.card()); + if (!updated) { + showThemedMessageDialog(parentWindow, "Failed to update card: " + updated.error(), + "Error", wxOK | wxICON_ERROR); + return; + } + refreshCollection(); +} + +void DigiBattle99GameView::onDeleteCard(wxWindow* parentWindow) { + if (listPanel_ == nullptr) return; + auto sel = listPanel_->selected(); + if (!sel) { + showThemedMessageDialog(parentWindow, "Select a card first.", "Delete", + wxOK | wxICON_INFORMATION); + return; + } + if (showThemedConfirmDialog(parentWindow, "Delete \"" + sel->name + "\"?", + "Confirm") != wxID_YES) { + return; + } + auto removed = collection_.remove(Game::DigiBattle99, sel->id); + if (!removed) { + showThemedMessageDialog(parentWindow, "Failed to delete card: " + removed.error(), + "Error", wxOK | wxICON_ERROR); + return; + } + refreshCollection(); +} + +std::string DigiBattle99GameView::onUpdateSets(wxWindow* parentWindow) { + auto out = sets_.updateSets(Game::DigiBattle99); + if (!out) { + showThemedMessageDialog(parentWindow, "Failed to update sets: " + out.error(), + "Error", wxOK | wxICON_ERROR); + return "Update failed"; + } + setsCache_ = out.value(); + showThemedMessageDialog( + parentWindow, + "Updated " + std::to_string(out.value().size()) + " Digimon (Digi-Battle) sets.", + "Sets updated", wxOK | wxICON_INFORMATION); + return "Digimon (Digi-Battle) sets updated."; +} + +void DigiBattle99GameView::setFilter(std::string_view filter) { + if (listPanel_) listPanel_->setFilter(filter); +} + +void DigiBattle99GameView::applyTheme(const ThemePalette& palette) { + if (listPanel_) listPanel_->applyTheme(palette); + if (selectedPanel_) selectedPanel_->applyTheme(palette); +} + +} // namespace ccm::ui diff --git a/ui_wx/src/DigiBattle99SelectedCardPanel.cpp b/ui_wx/src/DigiBattle99SelectedCardPanel.cpp new file mode 100644 index 0000000..e890d1f --- /dev/null +++ b/ui_wx/src/DigiBattle99SelectedCardPanel.cpp @@ -0,0 +1,84 @@ +#include "ccm/ui/DigiBattle99SelectedCardPanel.hpp" + +#include "ccm/ui/SvgIcons.hpp" + +#include + +namespace ccm::ui { + +namespace { +enum DigiBattle99DetailKey : int { + kName = 0, + kSet, + kSetNo, + kLanguage, + kCondition, + kAmount, + kHolo, + kFirstEdition, + kSigned, + kAltered, +}; +} // namespace + +DigiBattle99SelectedCardPanel::DigiBattle99SelectedCardPanel(wxWindow* parent, + ImageService& imageService, + CardPreviewService& cardPreview) + : BaseSelectedCardPanel(parent, imageService, cardPreview) { + buildLayout(); +} + +std::vector +DigiBattle99SelectedCardPanel::declareDetailRows() const { + return { + {"Name", kName, "(no card selected)"}, + {"Set", kSet, ""}, + {"Set #", kSetNo, ""}, + {"Language", kLanguage, ""}, + {"Condition", kCondition, ""}, + {"Amount", kAmount, ""}, + }; +} + +std::vector +DigiBattle99SelectedCardPanel::declareFlagIcons() const { + return { + {kSvgHolo, "Holo", kHolo}, + {kSvgFirstEdition, "1. Edition", kFirstEdition}, + {kSvgSigned, "Signed", kSigned}, + {kSvgAltered, "Altered", kAltered}, + }; +} + +std::string DigiBattle99SelectedCardPanel::detailValueFor(const DigiBattle99Card& card, + DetailKey key) const { + switch (key) { + case kName: return card.name; + case kSet: return card.set.name; + case kSetNo: return card.setNo; + case kLanguage: return std::string(to_string(card.language)); + case kCondition: return std::string(to_string(card.condition)); + case kAmount: return std::to_string(card.amount); + case kNoteKey: return card.note; + } + return {}; +} + +bool DigiBattle99SelectedCardPanel::isFlagSet(const DigiBattle99Card& card, + DetailKey key) const { + switch (key) { + case kHolo: return card.holo; + case kFirstEdition: return card.firstEdition; + case kSigned: return card.signed_; + case kAltered: return card.altered; + } + return false; +} + +std::tuple +DigiBattle99SelectedCardPanel::previewKey(const DigiBattle99Card& card) const { + // Middle slot is Set.name (pack display name) for digimoncard.io pack=. + return {card.name, card.set.name, card.setNo}; +} + +} // namespace ccm::ui diff --git a/ui_wx/src/MainFrame.cpp b/ui_wx/src/MainFrame.cpp index 4501510..d7d29d3 100644 --- a/ui_wx/src/MainFrame.cpp +++ b/ui_wx/src/MainFrame.cpp @@ -41,8 +41,10 @@ constexpr const char kFilterInputHint[] = "Filter"; std::string dirNameForGame(Game g) { switch (g) { - case Game::Magic: return "magic"; - case Game::Pokemon: return "pokemon"; + case Game::Magic: return "magic"; + case Game::Pokemon: return "pokemon"; + case Game::YuGiOh: return "yugioh"; + case Game::DigiBattle99: return "digibattle99"; } return "magic"; } @@ -67,7 +69,7 @@ void ensureDataStorageScaffold(const Configuration& cfg) { } } - for (Game game : {Game::Magic, Game::Pokemon}) { + for (Game game : allGames()) { const fs::path gameRoot = root / dirNameForGame(game); fs::create_directories(gameRoot / "images", ec); if (ec) continue; diff --git a/ui_wx/src/SettingsDialog.cpp b/ui_wx/src/SettingsDialog.cpp index 1e985a2..a941627 100644 --- a/ui_wx/src/SettingsDialog.cpp +++ b/ui_wx/src/SettingsDialog.cpp @@ -1,5 +1,6 @@ #include "ccm/ui/SettingsDialog.hpp" #include "ccm/ui/Theme.hpp" +#include "ccm/domain/Enums.hpp" #include #include @@ -9,6 +10,20 @@ namespace ccm::ui { +namespace { + +wxString displayLabelForGame(Game g) { + switch (g) { + case Game::Magic: return "Magic"; + case Game::Pokemon: return "Pokemon"; + case Game::YuGiOh: return "Yu-Gi-Oh!"; + case Game::DigiBattle99: return "Digimon (Digi-Battle)"; + } + return wxString::FromUTF8(to_string(g).data()); +} + +} // namespace + SettingsDialog::SettingsDialog(wxWindow* parent, ConfigService& config) : wxDialog(parent, wxID_ANY, "Settings", wxDefaultPosition, wxSize(560, 200), @@ -30,9 +45,14 @@ SettingsDialog::SettingsDialog(wxWindow* parent, ConfigService& config) gameRow->Add(new wxStaticText(this, wxID_ANY, "Default game:"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 6); defaultGameChoice_ = new wxChoice(this, wxID_ANY); - defaultGameChoice_->Append("Magic"); - defaultGameChoice_->Append("Pokemon"); - defaultGameChoice_->SetSelection(config_.current().defaultGame == Game::Magic ? 0 : 1); + int selected = 0; + int idx = 0; + for (const Game g : allGames()) { + defaultGameChoice_->Append(displayLabelForGame(g)); + if (g == config_.current().defaultGame) selected = idx; + ++idx; + } + defaultGameChoice_->SetSelection(selected); gameRow->Add(defaultGameChoice_, 0); root->Add(gameRow, 0, wxEXPAND | wxLEFT | wxRIGHT, 10); @@ -77,7 +97,11 @@ void SettingsDialog::onBrowse(wxCommandEvent&) { void SettingsDialog::onOk(wxCommandEvent& ev) { Configuration next = config_.current(); next.dataStorage = dataDirCtrl_->GetValue().ToStdString(); - next.defaultGame = defaultGameChoice_->GetSelection() == 0 ? Game::Magic : Game::Pokemon; + const int gameSel = defaultGameChoice_->GetSelection(); + const auto& games = allGames(); + if (gameSel >= 0 && static_cast(gameSel) < games.size()) { + next.defaultGame = games[static_cast(gameSel)]; + } switch (themeChoice_->GetSelection()) { case 1: next.theme = Theme::Dark; break; case 0: