summaryrefslogtreecommitdiff
path: root/internal/processor
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-02 22:18:09 +0300
committerPaul Buetow <paul@buetow.org>2026-04-02 22:18:09 +0300
commit373a10660bdd1faf27d22073380e5e897870ab12 (patch)
tree3d1e8a8b375aa509c0b4b2b540058cc3a4b3e200 /internal/processor
parentbd23c3f3e53bced44b5ecf0b0c6a74a3cc2f9875 (diff)
task zy: move GUI application launch out of Processor into cmd/main.go [SoC]
Replace Processor.RunGUIMode() with a standalone runGUIMode() function in the composition root (cmd/main.go) that calls proc.GUIConfig() to get the GUI settings and then owns the gui.New()/Run() lifecycle. The processor package still imports gui for the gui.Config return type; complete removal of that import is deferred to task 000 (god-object decomposition) where the Processor itself will be split up. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/processor')
-rw-r--r--internal/processor/processor.go46
-rw-r--r--internal/processor/processor_test.go14
2 files changed, 18 insertions, 42 deletions
diff --git a/internal/processor/processor.go b/internal/processor/processor.go
index c79e892..40487b9 100644
--- a/internal/processor/processor.go
+++ b/internal/processor/processor.go
@@ -16,7 +16,6 @@ import (
"codeberg.org/snonux/totalrecall/internal/audio"
"codeberg.org/snonux/totalrecall/internal/batch"
"codeberg.org/snonux/totalrecall/internal/cli"
- appconfig "codeberg.org/snonux/totalrecall/internal/config"
"codeberg.org/snonux/totalrecall/internal/gui"
"codeberg.org/snonux/totalrecall/internal/image"
"codeberg.org/snonux/totalrecall/internal/phonetic"
@@ -32,11 +31,11 @@ type Processor struct {
randomIntn func(n int) int
}
-var newOpenAIImageClient = func(config *image.OpenAIConfig) image.ImageSearcher {
+var newOpenAIImageClient = func(config *image.OpenAIConfig) image.ImageClient {
return image.NewOpenAIClient(config)
}
-var newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageSearcher {
+var newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageClient {
return image.NewNanoBananaClient(config)
}
@@ -681,34 +680,11 @@ func (p *Processor) GenerateAnkiFile() (string, error) {
return outputPath, nil
}
-// RunGUIMode launches the GUI application
-func (p *Processor) RunGUIMode() error {
- guiConfig := p.guiConfigForRunMode()
-
- // Only set OutputDir if it was explicitly provided via flag
- // Check if the outputDir is different from the default
- home, err := appconfig.HomeDir()
- if err != nil {
- fmt.Fprintf(os.Stderr, "Warning: %v\n", err)
- }
- defaultOutputDir := filepath.Join(home, "Downloads")
- if p.flags.OutputDir != defaultOutputDir {
- // User explicitly set a different output directory
- guiConfig.OutputDir = p.flags.OutputDir
- }
- if guiConfig.GoogleAPIKey == "" {
- guiConfig.GoogleAPIKey = cli.GetGoogleAPIKey()
- }
- // Otherwise, gui.New will use its own default (XDG state directory)
-
- // Create and run GUI application
- app := gui.New(guiConfig)
- app.Run()
-
- return nil
-}
-
-func (p *Processor) guiConfigForRunMode() *gui.Config {
+// GUIConfig returns a gui.Config populated from the processor's flags and
+// Viper settings. Callers (typically cmd/main.go) use this to construct the
+// GUI application so that gui.New() lives outside the processor package and
+// the processor→gui dependency is limited to the Config type only.
+func (p *Processor) GUIConfig() *gui.Config {
imageProvider := p.flags.ImageAPI
if !p.flags.ImageAPISpecified {
imageProvider = gui.DefaultConfig().ImageProvider
@@ -790,7 +766,7 @@ func (p *Processor) nanoBananaTextModelForRunMode() string {
return image.DefaultNanoBananaTextModel
}
-func (p *Processor) newImageSearcher() (image.ImageSearcher, error) {
+func (p *Processor) newImageSearcher() (image.ImageClient, error) {
provider := p.imageProviderForRunMode()
switch provider {
@@ -815,7 +791,7 @@ func (p *Processor) imageProviderForRunMode() string {
return strings.ToLower(strings.TrimSpace(p.flags.ImageAPI))
}
-func (p *Processor) newOpenAIImageSearcher() (image.ImageSearcher, error) {
+func (p *Processor) newOpenAIImageSearcher() (image.ImageClient, error) {
openaiConfig := &image.OpenAIConfig{
APIKey: cli.GetOpenAIKey(),
Model: p.flags.OpenAIImageModel,
@@ -844,7 +820,7 @@ func (p *Processor) newOpenAIImageSearcher() (image.ImageSearcher, error) {
return newOpenAIImageClient(openaiConfig), nil
}
-func (p *Processor) newNanoBananaImageSearcher() (image.ImageSearcher, error) {
+func (p *Processor) newNanoBananaImageSearcher() (image.ImageClient, error) {
nanoBananaConfig := &image.NanoBananaConfig{
APIKey: cli.GetGoogleAPIKey(),
Model: p.flags.NanoBananaModel,
@@ -865,7 +841,7 @@ func (p *Processor) newNanoBananaImageSearcher() (image.ImageSearcher, error) {
return newNanoBananaImageClient(nanoBananaConfig), nil
}
-func (p *Processor) saveImagePrompt(wordDir string, searcher image.ImageSearcher) {
+func (p *Processor) saveImagePrompt(wordDir string, searcher image.ImageClient) {
type promptGetter interface {
GetLastPrompt() string
}
diff --git a/internal/processor/processor_test.go b/internal/processor/processor_test.go
index db03266..cfa4545 100644
--- a/internal/processor/processor_test.go
+++ b/internal/processor/processor_test.go
@@ -274,7 +274,7 @@ func TestGUIConfigForRunModeUsesNanoBananaDefaultWhenImageAPIIsNotSpecified(t *t
flags.ImageAPISpecified = false
p := NewProcessor(flags)
- guiConfig := p.guiConfigForRunMode()
+ guiConfig := p.GUIConfig()
if guiConfig.ImageProvider != gui.DefaultConfig().ImageProvider {
t.Fatalf("guiConfig.ImageProvider = %q, want GUI default %q", guiConfig.ImageProvider, gui.DefaultConfig().ImageProvider)
}
@@ -314,7 +314,7 @@ func TestGUIConfigForRunModeHonorsExplicitImageAPI(t *testing.T) {
flags.ImageAPISpecified = true
p := NewProcessor(flags)
- guiConfig := p.guiConfigForRunMode()
+ guiConfig := p.GUIConfig()
if guiConfig.ImageProvider != "openai" {
t.Fatalf("guiConfig.ImageProvider = %q, want %q", guiConfig.ImageProvider, "openai")
}
@@ -348,7 +348,7 @@ func TestGUIConfigForRunModeHonorsExplicitNanoBananaModelFlags(t *testing.T) {
flags.NanoBananaTextModelSpecified = true
p := NewProcessor(flags)
- guiConfig := p.guiConfigForRunMode()
+ guiConfig := p.GUIConfig()
if guiConfig.NanoBananaModel != "flag-image-model" {
t.Fatalf("guiConfig.NanoBananaModel = %q, want %q", guiConfig.NanoBananaModel, "flag-image-model")
}
@@ -1218,7 +1218,7 @@ func TestDownloadImagesWithTranslationUsesNanoBananaConfigAndSavesPrompt(t *test
originalConstructor := newNanoBananaImageClient
stubSearcher := &stubImageSearcher{}
capturedConfig := new(image.NanoBananaConfig)
- newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageSearcher {
+ newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageClient {
*capturedConfig = *config
return stubSearcher
}
@@ -1274,7 +1274,7 @@ func TestDownloadImagesWithTranslationPersistsPromptWhenDownloadFails(t *testing
originalConstructor := newNanoBananaImageClient
stubSearcher := &stubImageSearcher{downloadErr: errors.New("download failed")}
- newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageSearcher {
+ newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageClient {
return stubSearcher
}
t.Cleanup(func() {
@@ -1323,7 +1323,7 @@ func TestDownloadImagesWithTranslationUsesConfiguredNanoBananaWhenImageAPINotSpe
originalConstructor := newNanoBananaImageClient
stubSearcher := &stubImageSearcher{}
capturedConfig := new(image.NanoBananaConfig)
- newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageSearcher {
+ newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageClient {
*capturedConfig = *config
return stubSearcher
}
@@ -1429,7 +1429,7 @@ func TestNewNanoBananaImageSearcherExplicitDefaultWinsOverConfig(t *testing.T) {
originalConstructor := newNanoBananaImageClient
capturedConfig := new(image.NanoBananaConfig)
- newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageSearcher {
+ newNanoBananaImageClient = func(config *image.NanoBananaConfig) image.ImageClient {
*capturedConfig = *config
return &stubImageSearcher{}
}