summaryrefslogtreecommitdiff
path: root/internal/gui
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-08 09:59:23 +0300
committerPaul Buetow <paul@buetow.org>2026-04-08 09:59:23 +0300
commit35a3c860f63403d14c83668dcdd017b6ef517fbf (patch)
tree1b348348fc951747d689cc62bd7bbbc42c94fa11 /internal/gui
parentef1eefce9a1515a17490d6624ef88f2ef41330e1 (diff)
refactor(dip): inject archive, models, story, and gui at composition roots
Define Archiver, ModelLister, and StoryRunner interfaces in their packages. gui.New returns App; Application carries an injectable Archiver from Config. cmd/totalrecall wires default implementations via runDeps for tests and DI. Made-with: Cursor
Diffstat (limited to 'internal/gui')
-rw-r--r--internal/gui/app.go23
1 files changed, 19 insertions, 4 deletions
diff --git a/internal/gui/app.go b/internal/gui/app.go
index 6c1cf21..0c821d4 100644
--- a/internal/gui/app.go
+++ b/internal/gui/app.go
@@ -30,6 +30,12 @@ import (
"codeberg.org/snonux/totalrecall/internal/translation"
)
+// App is the runnable GUI application constructed at the composition root
+// (cmd/totalrecall). Callers invoke Run() to start the Fyne event loop.
+type App interface {
+ Run()
+}
+
// Application represents the main GUI application
type Application struct {
// Fyne components
@@ -88,6 +94,7 @@ type Application struct {
// Configuration
config *Config
+ archiver archive.Archiver
audioConfig *audio.Config
phoneticFetcher *phonetic.Fetcher
translator *translation.Translator
@@ -144,6 +151,9 @@ type Config struct {
// constructing new instances from the provider/key fields above.
PhoneticFetcher *phonetic.Fetcher
Translator *translation.Translator
+ // Archiver moves the cards directory to a timestamped archive; nil uses
+ // archive.DefaultArchiver.
+ Archiver archive.Archiver
}
// DefaultConfig returns default GUI configuration
@@ -170,13 +180,17 @@ func DefaultConfig() *Config {
}
}
-// New creates a new GUI application
-// New constructs and returns a fully initialised Application for the given config.
+// New constructs and returns a fully initialised App for the given config.
// A nil config receives all defaults. The Fyne application and UI are created here;
// callers should call Run() to start the event loop.
-func New(config *Config) *Application {
+func New(config *Config) App {
config = applyConfigDefaults(config)
+ arch := config.Archiver
+ if arch == nil {
+ arch = archive.DefaultArchiver{}
+ }
+
if err := os.MkdirAll(config.OutputDir, 0755); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to create output directory %q: %v\n", config.OutputDir, err)
}
@@ -188,6 +202,7 @@ func New(config *Config) *Application {
a := &Application{
app: myApp,
config: config,
+ archiver: arch,
ctx: ctx,
cancel: cancel,
savedCards: make([]anki.Card, 0),
@@ -1479,7 +1494,7 @@ func (a *Application) performArchive() {
}
cardsDir := filepath.Join(home, ".local", "state", "totalrecall", "cards")
- if err := archive.ArchiveCards(cardsDir); err != nil {
+ if err := a.archiver.ArchiveCards(cardsDir); err != nil {
dialog.ShowError(err, a.window)
return
}