Files
Card-Collection-Manager-3/app/main.cpp
T
Sebastian Dine 55ace147bc major: initial release
* initial development

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* pokemon

* pokemon

* pokemon

* pokemon

* pokemon

* pokemon

* improvements

* improvements

* ci/cd

* ci/cd

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

---------

Co-authored-by: sdine <sdine@sdine.com>
2026-05-09 11:05:47 +02:00

146 lines
6.3 KiB
C++

// Composition root: builds the dependency graph from the bottom up and hands
// 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/MagicCard.hpp"
#include "ccm/domain/PokemonCard.hpp"
#include "ccm/games/magic/MagicGameModule.hpp"
#include "ccm/games/pokemon/PokemonGameModule.hpp"
#include "ccm/infra/CprHttpClient.hpp"
#include "ccm/infra/JsonCollectionRepository.hpp"
#include "ccm/infra/JsonSetRepository.hpp"
#include "ccm/infra/LocalImageStore.hpp"
#include "ccm/infra/StdFileSystem.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/AppContext.hpp"
#include "ccm/ui/MagicGameView.hpp"
#include "ccm/ui/MainFrame.hpp"
#include "ccm/ui/PokemonGameView.hpp"
#include <wx/app.h>
#include <wx/icon.h>
#include <wx/image.h>
#include <wx/msgdlg.h>
#include <wx/stdpaths.h>
#include <wx/utils.h>
#include <filesystem>
#include <memory>
#include <string>
namespace {
// All Game::X -> directory string mappings live in one place. Eliminates the
// 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";
}
return "magic";
}
} // namespace
class CcmApp : public wxApp {
public:
bool OnInit() override {
// wxImage knows about PNG/JPEG once these handlers are registered.
wxImage::AddHandler(new wxPNGHandler);
wxImage::AddHandler(new wxJPEGHandler);
// --- locate config next to exe, data in user home ----------------
const std::filesystem::path exeDir =
std::filesystem::path(wxStandardPaths::Get().GetExecutablePath().ToStdString())
.parent_path();
const auto configPath = exeDir / "config.json";
const auto defaultDataDir =
std::filesystem::path(wxGetHomeDir().ToStdString()) / "ccm3-data";
// --- build the dependency graph -----------------------------------
fs_ = std::make_unique<ccm::StdFileSystem>();
config_ = std::make_unique<ccm::ConfigService>(*fs_, configPath, defaultDataDir);
if (auto init = config_->initialize(); !init) {
wxMessageBox("Failed to load configuration: " + init.error(),
"Startup error", wxOK | wxICON_ERROR);
return false;
}
http_ = std::make_unique<ccm::CprHttpClient>();
magicMod_ = std::make_unique<ccm::MagicGameModule>(*http_);
pokeMod_ = std::make_unique<ccm::PokemonGameModule>(*http_);
magicRepo_ = std::make_unique<ccm::JsonCollectionRepository<ccm::MagicCard>>(
*fs_, *config_, &dirNameForGame);
pokeRepo_ = std::make_unique<ccm::JsonCollectionRepository<ccm::PokemonCard>>(
*fs_, *config_, &dirNameForGame);
setRepo_ = std::make_unique<ccm::JsonSetRepository>(*fs_, *config_, &dirNameForGame);
imgStore_ = std::make_unique<ccm::LocalImageStore>(*fs_, *config_, &dirNameForGame);
imgSvc_ = std::make_unique<ccm::ImageService>(*imgStore_);
magicCollSvc_ = std::make_unique<ccm::CollectionService<ccm::MagicCard>>(
*magicRepo_, *imgStore_);
pokeCollSvc_ = std::make_unique<ccm::CollectionService<ccm::PokemonCard>>(
*pokeRepo_, *imgStore_);
setSvc_ = std::make_unique<ccm::SetService>(*setRepo_);
setSvc_->registerModule(magicMod_.get());
setSvc_->registerModule(pokeMod_.get());
previewSvc_ = std::make_unique<ccm::CardPreviewService>(*http_);
previewSvc_->registerModule(*magicMod_);
previewSvc_->registerModule(*pokeMod_);
// Per-game UI bundles. Order here is the order shown in the Game menu.
magicView_ = std::make_unique<ccm::ui::MagicGameView>(
*config_, *magicCollSvc_, *setSvc_, *imgSvc_, *previewSvc_, *magicMod_);
pokeView_ = std::make_unique<ccm::ui::PokemonGameView>(
*config_, *pokeCollSvc_, *setSvc_, *imgSvc_, *previewSvc_, *pokeMod_);
ctx_ = std::make_unique<ccm::ui::AppContext>(ccm::ui::AppContext{
*config_,
*setSvc_,
*imgSvc_,
*previewSvc_,
*magicMod_,
*pokeMod_,
{ magicView_.get(), pokeView_.get() },
});
auto* frame = new ccm::ui::MainFrame(*ctx_);
#ifdef __WXMSW__
frame->SetIcon(wxICON(ccm_main_icon));
#endif
frame->Show(true);
return true;
}
private:
// Order matters - destruction is reverse, so put services that depend on
// others *after* their deps in the member list. Game views are torn down
// first so their panels release any references to the typed services.
std::unique_ptr<ccm::StdFileSystem> fs_;
std::unique_ptr<ccm::ConfigService> config_;
std::unique_ptr<ccm::CprHttpClient> http_;
std::unique_ptr<ccm::MagicGameModule> magicMod_;
std::unique_ptr<ccm::PokemonGameModule> pokeMod_;
std::unique_ptr<ccm::JsonCollectionRepository<ccm::MagicCard>> magicRepo_;
std::unique_ptr<ccm::JsonCollectionRepository<ccm::PokemonCard>> pokeRepo_;
std::unique_ptr<ccm::JsonSetRepository> setRepo_;
std::unique_ptr<ccm::LocalImageStore> imgStore_;
std::unique_ptr<ccm::ImageService> imgSvc_;
std::unique_ptr<ccm::CollectionService<ccm::MagicCard>> magicCollSvc_;
std::unique_ptr<ccm::CollectionService<ccm::PokemonCard>> pokeCollSvc_;
std::unique_ptr<ccm::SetService> setSvc_;
std::unique_ptr<ccm::CardPreviewService> previewSvc_;
std::unique_ptr<ccm::ui::MagicGameView> magicView_;
std::unique_ptr<ccm::ui::PokemonGameView> pokeView_;
std::unique_ptr<ccm::ui::AppContext> ctx_;
};
wxIMPLEMENT_APP(CcmApp);