gui

package
v0.29.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 39 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetAppIcon

func GetAppIcon() fyne.Resource

GetAppIcon returns the application icon as a Fyne resource

func ResourceFromPath

func ResourceFromPath(path string) (fyne.Resource, error)

ResourceFromPath creates a Fyne resource from a file path

Types

type App

type App interface {
	Run()
}

App is the runnable GUI application constructed at the composition root (cmd/totalrecall). Callers invoke Run() to start the Fyne event loop.

func New

func New(config *Config) App

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.

type Application

type Application struct {
	// contains filtered or unexported fields
}

Application represents the main GUI application

func (*Application) Run

func (a *Application) Run()

Run starts the GUI application

type AudioConfigResolver

type AudioConfigResolver struct {
	// contains filtered or unexported fields
}

AudioConfigResolver derives effective TTS provider settings from the GUI config and the shared audio.Config. It centralizes provider name, voice list, output format, and per-run audio.Config construction so orchestration code does not repeat string handling and defaults.

func NewAudioConfigResolver

func NewAudioConfigResolver(guiConfig *Config, audioConfig *audio.Config) *AudioConfigResolver

NewAudioConfigResolver builds a resolver for the given GUI and audio settings. Either pointer may be nil; defaults match the previous GenerationOrchestrator behaviour.

func (*AudioConfigResolver) BaseConfigForAttribution

func (r *AudioConfigResolver) BaseConfigForAttribution() *audio.Config

BaseConfigForAttribution returns the configured audio.Config pointer, or the package default when unset — matching how attribution sidecars resolve the base parameters before per-run voice/speed overrides.

func (*AudioConfigResolver) ConfigForGeneration

func (r *AudioConfigResolver) ConfigForGeneration(voice string, speed float64) audio.Config

ConfigForGeneration builds an audio.Config for a single generation call, overriding the voice and speed with the values selected for this run.

func (*AudioConfigResolver) OutputFormat

func (r *AudioConfigResolver) OutputFormat() string

OutputFormat resolves the effective output format (e.g. "mp3" or "wav").

func (*AudioConfigResolver) ProviderName

func (r *AudioConfigResolver) ProviderName() string

ProviderName returns the lowercase provider name from config, defaulting to the shared audio default when none is set.

func (*AudioConfigResolver) Voices

func (r *AudioConfigResolver) Voices() []string

Voices returns the configured provider's voice list.

type AudioPlayer

type AudioPlayer struct {
	widget.BaseWidget
	// contains filtered or unexported fields
}

AudioPlayer is a custom widget for playing audio files

func NewAudioPlayer

func NewAudioPlayer() *AudioPlayer

NewAudioPlayer creates a new audio player widget. Call SetContext before use so that post-playback UI updates are guarded against the app shutting down.

func (*AudioPlayer) Clear

func (p *AudioPlayer) Clear()

Clear clears the audio player

func (*AudioPlayer) CreateRenderer

func (p *AudioPlayer) CreateRenderer() fyne.WidgetRenderer

CreateRenderer implements fyne.Widget

func (*AudioPlayer) Play

func (p *AudioPlayer) Play()

Play triggers audio playback

func (*AudioPlayer) PlayBack

func (p *AudioPlayer) PlayBack()

PlayBack triggers back audio playback (for bg-bg cards)

func (*AudioPlayer) SetAudioFile

func (p *AudioPlayer) SetAudioFile(audioFile string)

SetAudioFile sets the audio file to play and optionally auto-plays it

func (*AudioPlayer) SetAudioFileNoAutoPlay

func (p *AudioPlayer) SetAudioFileNoAutoPlay(audioFile string)

SetAudioFileNoAutoPlay sets the audio file without auto-playing Used when regenerating audio on bg-bg cards - we only want to play when explicitly requested

func (*AudioPlayer) SetAutoPlayEnabled

func (p *AudioPlayer) SetAutoPlayEnabled(autoPlayEnabled *bool)

SetAutoPlayEnabled sets the reference to the auto-play state

func (*AudioPlayer) SetBackAudioFile

func (p *AudioPlayer) SetBackAudioFile(audioFile string)

SetBackAudioFile sets the back audio file for bg-bg cards

func (*AudioPlayer) SetContext

func (p *AudioPlayer) SetContext(ctx context.Context)

SetContext wires the application lifecycle context into the player. The post-playback UI update goroutine checks this context before calling fyne.Do, preventing writes to freed widgets after the window is closed (Go Mistake #62). Must be called before the first playback attempt.

func (*AudioPlayer) SetPhonetic

func (p *AudioPlayer) SetPhonetic(phonetic string)

SetPhonetic sets the phonetic transcription text

type CardFiles

type CardFiles struct {
	WordDir      string
	Translation  string
	AudioFile    string
	AudioBack    string
	ImageFile    string
	PhoneticInfo string
	ImagePrompt  string
	CardType     internal.CardType
}

CardFiles holds the paths to all files loaded for a single card.

type CardService

type CardService struct {
	// contains filtered or unexported fields
}

CardService manages card file discovery, directory creation, persistence, and state loading from the output directory. It is responsible for all non-UI file I/O related to cards, decoupled from UI event-wiring. Directory-scanning and creation are delegated to a store.CardStore so the underlying algorithm is shared with the processor package (DRY).

func NewCardService

func NewCardService(config *Config) *CardService

NewCardService constructs a CardService for the given configuration. It initialises an internal store.CardStore rooted at config.OutputDir.

func (*CardService) CheckMissingFiles

func (cs *CardService) CheckMissingFiles(word string, existingAudio, existingAudioBack, existingImage, existingTranslation, existingPrompt, existingPhonetic string, cardType string) *CardFiles

CheckMissingFiles inspects a card directory for any files that have appeared since the last load and returns a partial CardFiles with only the newly found fields populated. Callers should merge with existing state.

func (*CardService) DeleteWord

func (cs *CardService) DeleteWord(word string, existingWords []string, savedCards []anki.Card) ([]string, []anki.Card, error)

DeleteWord moves the card directory for a word to the trash bin directory. Returns the updated existingWords slice and updatedSavedCards slice.

func (*CardService) EnsureCardDirectory

func (cs *CardService) EnsureCardDirectory(word string) (string, error)

EnsureCardDirectory ensures a card directory exists for the given word and returns its path. Creates it with metadata if it does not exist yet.

func (*CardService) EnsureWordDirectoryAndMetadata

func (cs *CardService) EnsureWordDirectoryAndMetadata(word string) (string, error)

EnsureWordDirectoryAndMetadata creates a new card directory and writes word metadata to word.txt inside it. Returns the directory path. Uses store.FindOrCreateCardDirectory so the creation logic is not duplicated.

func (*CardService) FindCardDirectory

func (cs *CardService) FindCardDirectory(word string) string

FindCardDirectory finds the directory for a given Bulgarian word. Delegates to the shared store.CardStore which also handles the legacy _word.txt fallback for backward compatibility.

func (*CardService) LoadCardFiles

func (cs *CardService) LoadCardFiles(word string) *CardFiles

LoadCardFiles loads all available files for the given word from disk. Returns nil if no card directory exists for the word.

func (*CardService) LoadImagePromptForWord

func (cs *CardService) LoadImagePromptForWord(word string) string

LoadImagePromptForWord reads the image_prompt.txt file for the given word. Returns empty string if not found.

func (*CardService) LoadPhoneticInfo

func (cs *CardService) LoadPhoneticInfo(word string) string

LoadPhoneticInfo reads phonetic information from disk for the given word. Returns empty string if not found.

func (*CardService) SavePhoneticInfo

func (cs *CardService) SavePhoneticInfo(word, phoneticText string) error

SavePhoneticInfo persists phonetic information for the given word to disk.

func (*CardService) SaveTranslation

func (cs *CardService) SaveTranslation(word, translation string) error

SaveTranslation persists the translation for the given word to disk. It finds or creates the card directory as necessary.

func (*CardService) ScanExistingWords

func (cs *CardService) ScanExistingWords() []string

ScanExistingWords scans the output directory for existing card subdirectories and returns a sorted list of the Bulgarian words found. A directory counts only if it contains at least one of: an audio file, an image, or a translation file. Delegates iteration and word-file reading to the shared store.CardStore so that logic is not duplicated here.

type Config

type Config struct {
	OutputDir   string
	AudioFormat string
	// AudioProvider selects the TTS backend used by the GUI.
	AudioProvider string
	ImageProvider string
	OpenAIKey     string
	GoogleAPIKey  string
	// NanoBananaModel selects the Gemini image model for Nano Banana generation.
	NanoBananaModel string
	// NanoBananaTextModel selects the Gemini text model for Nano Banana prompt generation.
	NanoBananaTextModel string
	// GeminiTTSModel selects the Gemini TTS model when Gemini audio is active.
	GeminiTTSModel string
	// GeminiVoice selects a specific Gemini voice; empty picks a random Gemini voice.
	GeminiVoice         string
	TranslationProvider translation.Provider
	PhoneticProvider    phonetic.Provider
	AutoPlay            bool // Whether to automatically play audio when generated or navigated to

	// Injectable dependencies — when non-nil, New() uses them directly instead of
	// 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
}

Config holds GUI application configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns default GUI configuration

type CustomEntry

type CustomEntry struct {
	widget.Entry
	// contains filtered or unexported fields
}

CustomEntry extends widget.Entry to handle Escape key (single-line version)

func NewCustomEntry

func NewCustomEntry() *CustomEntry

NewCustomEntry creates a new custom single-line entry

func (*CustomEntry) SetOnEscape

func (e *CustomEntry) SetOnEscape(f func())

SetOnEscape sets the callback for when Escape is pressed

func (*CustomEntry) TypedKey

func (e *CustomEntry) TypedKey(key *fyne.KeyEvent)

TypedKey handles key events

type CustomMultiLineEntry

type CustomMultiLineEntry struct {
	widget.Entry
	// contains filtered or unexported fields
}

CustomMultiLineEntry extends widget.Entry to handle Escape key

func NewCustomMultiLineEntry

func NewCustomMultiLineEntry() *CustomMultiLineEntry

NewCustomMultiLineEntry creates a new custom multi-line entry

func (*CustomMultiLineEntry) SetOnEscape

func (e *CustomMultiLineEntry) SetOnEscape(f func())

SetOnEscape sets the callback for when Escape is pressed

func (*CustomMultiLineEntry) TypedKey

func (e *CustomMultiLineEntry) TypedKey(key *fyne.KeyEvent)

TypedKey handles key events

type ExportHandler

type ExportHandler struct {
	// contains filtered or unexported fields
}

ExportHandler owns the Export to Anki dialog and APKG/CSV export paths (SRP).

type GenerateResult

type GenerateResult struct {
	AudioFile     string
	AudioFileBack string
	ImageFile     string
	PhoneticInfo  string
}

GenerateResult holds the outcome of a parallel generation run.

type GenerationOrchestrator

type GenerationOrchestrator struct {
	// contains filtered or unexported fields
}

GenerationOrchestrator coordinates audio, image, and phonetics generation for a single card. It holds all injectable factory functions so tests can substitute fakes without touching the UI layer. image.ClientFactories groups the two image-factory functions so the field definitions are not duplicated between this type and processor.Processor.

func NewGenerationOrchestrator

func NewGenerationOrchestrator(
	config *Config,
	audioCfg *audio.Config,
	phonetics *phonetic.Fetcher,
	translator *translation.Translator,
	imageFactories image.ClientFactories,
	newAudio audio.ProviderFactory,
) *GenerationOrchestrator

NewGenerationOrchestrator constructs an orchestrator wired to the given app configuration and service dependencies. imageFactories and newAudio are the injectable test seams — pass image.DefaultClientFactories() and audio.NewProvider for production behaviour.

func (*GenerationOrchestrator) GenerateAudio

func (o *GenerationOrchestrator) GenerateAudio(ctx context.Context, word, cardDir string) (string, error)

GenerateAudio generates audio for an en-bg card's single audio file. Returns the path to the generated file.

func (*GenerationOrchestrator) GenerateAudioBack

func (o *GenerationOrchestrator) GenerateAudioBack(ctx context.Context, text, cardDir string) (string, error)

GenerateAudioBack generates the back audio file for a bg-bg card.

func (*GenerationOrchestrator) GenerateAudioBgBg

func (o *GenerationOrchestrator) GenerateAudioBgBg(ctx context.Context, front, back, cardDir string) (string, string, error)

GenerateAudioBgBg generates audio for both sides of a bg-bg card in a single call, using the same voice for both to maintain consistency.

func (*GenerationOrchestrator) GenerateAudioFront

func (o *GenerationOrchestrator) GenerateAudioFront(ctx context.Context, word, cardDir string) (string, error)

GenerateAudioFront generates the front audio file for a bg-bg card.

func (*GenerationOrchestrator) GenerateImagesWithPrompt

func (o *GenerationOrchestrator) GenerateImagesWithPrompt(ctx context.Context, word, customPrompt, translation, cardDir string) (string, error)

GenerateImagesWithPrompt downloads a single image for a word, using an optional custom prompt and translation hint.

func (*GenerationOrchestrator) GenerateMaterials

func (o *GenerationOrchestrator) GenerateMaterials(
	ctx context.Context,
	word, translation, cardDir string,
	isBgBg bool,
	imagePrompt string,
	promptUI func(prompt string),
) (GenerateResult, error)

GenerateMaterials generates audio, image, and phonetics in parallel for a word. translation is the existing translation (may be empty). isBgBg flags bg-bg card type. imagePrompt is an optional custom prompt; imageTranslation is the translation hint for image prompts. The promptUI callback is called on the generating goroutine when the image prompt becomes known so callers can update the UI. Returns a GenerateResult or an error if any mandatory step fails.

func (*GenerationOrchestrator) GetPhoneticInfo

func (o *GenerationOrchestrator) GetPhoneticInfo(word string) (string, error)

GetPhoneticInfo fetches phonetic information for a Bulgarian word.

func (*GenerationOrchestrator) TranslateEnglishToBulgarian

func (o *GenerationOrchestrator) TranslateEnglishToBulgarian(word string) (string, error)

TranslateEnglishToBulgarian translates an English word to Bulgarian.

func (*GenerationOrchestrator) TranslateWord

func (o *GenerationOrchestrator) TranslateWord(word string) (string, error)

TranslateWord translates a Bulgarian word to English.

type ImageDisplay

type ImageDisplay struct {
	widget.BaseWidget
	// contains filtered or unexported fields
}

ImageDisplay is a custom widget for displaying images

func NewImageDisplay

func NewImageDisplay() *ImageDisplay

NewImageDisplay creates a new image display widget

func (*ImageDisplay) Clear

func (d *ImageDisplay) Clear()

Clear clears the display

func (*ImageDisplay) CreateRenderer

func (d *ImageDisplay) CreateRenderer() fyne.WidgetRenderer

CreateRenderer implements fyne.Widget

func (*ImageDisplay) SetGenerating

func (d *ImageDisplay) SetGenerating()

SetGenerating shows a generating status

func (*ImageDisplay) SetImage

func (d *ImageDisplay) SetImage(imagePath string)

SetImage sets a single image to display

func (*ImageDisplay) SetImages

func (d *ImageDisplay) SetImages(images []string)

SetImages sets multiple images but only displays the first one

type JobStatus

type JobStatus int

JobStatus represents the current state of a job

const (
	StatusQueued JobStatus = iota
	StatusProcessing
	StatusCompleted
	StatusFailed
)

func (JobStatus) String

func (s JobStatus) String() string

type KeyboardShortcuts

type KeyboardShortcuts struct {
	// contains filtered or unexported fields
}

KeyboardShortcuts wires global canvas shortcuts and the hotkey help dialog (SRP).

type LogViewer

type LogViewer struct {
	widget.BaseWidget
	// contains filtered or unexported fields
}

LogViewer is a widget that displays log messages

func NewLogViewer

func NewLogViewer() *LogViewer

NewLogViewer creates a new log viewer widget

func (*LogViewer) AddMessage

func (v *LogViewer) AddMessage(message string)

AddMessage adds a message to the log

func (*LogViewer) Clear

func (v *LogViewer) Clear()

Clear clears all log messages

func (*LogViewer) CreateRenderer

func (v *LogViewer) CreateRenderer() fyne.WidgetRenderer

CreateRenderer implements fyne.Widget

func (*LogViewer) Log

func (v *LogViewer) Log(format string, args ...interface{})

Log adds a message without timestamp (for internal use)

func (*LogViewer) StartCapture

func (v *LogViewer) StartCapture()

StartCapture starts capturing stdout and stderr

func (*LogViewer) StopCapture

func (v *LogViewer) StopCapture()

StopCapture stops capturing stdout and stderr

type LogWriter

type LogWriter struct {
	// contains filtered or unexported fields
}

LogWriter is a custom writer that captures log output

func (*LogWriter) Write

func (w *LogWriter) Write(p []byte) (n int, err error)

Write implements io.Writer

type NavigationHandler struct {
	// contains filtered or unexported fields
}

NavigationHandler owns word list navigation, loading card files from disk or queue state, file-check polling, and delete-to-trash. It holds a reference to Application for shared UI state and services (SRP: navigation vs generation).

type ParallelRunner

type ParallelRunner struct{}

ParallelRunner coordinates parallel audio, image, and phonetics work for material generation. It is stateless; the orchestrator supplies all behaviour via the first method argument.

func (ParallelRunner) GenerateMaterials

func (ParallelRunner) GenerateMaterials(
	o *GenerationOrchestrator,
	ctx context.Context,
	word, translation, cardDir string,
	isBgBg bool,
	imagePrompt string,
	promptUI func(prompt string),
) (GenerateResult, error)

GenerateMaterials generates audio, image, and phonetics in parallel for a word. translation is the existing translation (may be empty). isBgBg flags bg-bg card type. imagePrompt is an optional custom prompt; imageTranslation is the translation hint for image prompts. The promptUI callback is called on the generating goroutine when the image prompt becomes known so callers can update the UI. Returns a GenerateResult or an error if any mandatory step fails.

type QueueManager

type QueueManager struct {
	// contains filtered or unexported fields
}

QueueManager owns background word-job processing: card contexts, active operation counts, queue draining, and the queue status label (SRP).

type VoiceSelector

type VoiceSelector struct {
	// contains filtered or unexported fields
}

VoiceSelector picks voice and speed for a generation run from an AudioConfigResolver. For Gemini with a pinned voice the configured voice is used; otherwise a random voice is selected from the available list.

func NewVoiceSelector

func NewVoiceSelector(resolver *AudioConfigResolver) *VoiceSelector

NewVoiceSelector constructs a VoiceSelector backed by the given resolver.

func (*VoiceSelector) GeminiSpeed

func (v *VoiceSelector) GeminiSpeed() float64

GeminiSpeed returns the configured Gemini TTS speed or the default.

func (*VoiceSelector) GeminiVoicePinned

func (v *VoiceSelector) GeminiVoicePinned() bool

GeminiVoicePinned reports whether a specific Gemini voice is locked in config, meaning fallback voice selection should be skipped.

func (*VoiceSelector) VoiceAndSpeed

func (v *VoiceSelector) VoiceAndSpeed() (string, float64)

VoiceAndSpeed selects the voice and speed for a generation run.

type WordJob

type WordJob struct {
	ID               int
	Word             string
	Translation      string
	AudioFile        string
	AudioFileBack    string // Back audio file (only for bg-bg cards)
	ImageFile        string // Changed from ImageFiles []string to single image
	Status           JobStatus
	Error            error
	StartedAt        time.Time
	CompletedAt      time.Time
	CustomPrompt     string // Custom prompt for image generation
	NeedsTranslation bool   // Whether translation is needed
	CardType         string // Card type: "en-bg" or "bg-bg"
}

WordJob represents a single word processing job

type WordQueue

type WordQueue struct {
	// contains filtered or unexported fields
}

WordQueue manages the queue of words to be processed

func NewWordQueue

func NewWordQueue(ctx context.Context) *WordQueue

NewWordQueue creates a new word processing queue

func (*WordQueue) AddWord

func (q *WordQueue) AddWord(word string) *WordJob

AddWord adds a word to the processing queue

func (*WordQueue) AddWordWithPrompt

func (q *WordQueue) AddWordWithPrompt(word, customPrompt string) *WordJob

AddWordWithPrompt adds a word to the processing queue with a custom prompt

func (*WordQueue) CompleteJob

func (q *WordQueue) CompleteJob(jobID int, translation, audioFile, audioFileBack, imageFile string)

CompleteJob marks a job as completed with results

func (*WordQueue) FailJob

func (q *WordQueue) FailJob(jobID int, err error)

FailJob marks a job as failed with an error

func (*WordQueue) GetActiveJobs

func (q *WordQueue) GetActiveJobs() []*WordJob

GetActiveJobs returns all jobs that are currently queued or processing. It uses only q.processing and q.results under the read lock; it does not touch q.jobs, because channel operations must not run while holding the mutex (other goroutines send/receive on q.jobs without the lock).

func (*WordQueue) GetCompletedJobs

func (q *WordQueue) GetCompletedJobs() []*WordJob

GetCompletedJobs returns all completed jobs

func (*WordQueue) GetJob

func (q *WordQueue) GetJob(id int) *WordJob

GetJob returns a job by ID

func (*WordQueue) GetQueueStatus

func (q *WordQueue) GetQueueStatus() (queued, processing, completed, failed int)

GetQueueStatus returns the current queue statistics

func (*WordQueue) IsWordProcessing

func (q *WordQueue) IsWordProcessing(word string) bool

IsWordProcessing checks if a word is currently being processed or queued

func (*WordQueue) ProcessNextJob

func (q *WordQueue) ProcessNextJob() *WordJob

ProcessNextJob should be called by the GUI to process the next job in queue

func (*WordQueue) RemoveCompletedJobByWord

func (q *WordQueue) RemoveCompletedJobByWord(word string)

RemoveCompletedJobByWord removes a completed job for a specific word

func (*WordQueue) SetCallbacks

func (q *WordQueue) SetCallbacks(onStatusUpdate func(*WordJob), onJobComplete func(*WordJob))

SetCallbacks sets the callback functions for UI updates

func (*WordQueue) Stop

func (q *WordQueue) Stop()

Stop gracefully shuts down the queue

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL