summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-18 08:34:16 +0300
committerPaul Buetow <paul@buetow.org>2025-07-18 08:34:16 +0300
commite2f45921c45c9322c2ddb679d0511ba20772dcae (patch)
tree85e13d7d4127bd1fdc4821427782475095c6f289
parent85ee3559fcdee46a21c4e9a5ef9ec519d997c447 (diff)
gui improvements
-rw-r--r--internal/gui/app.go91
-rw-r--r--internal/gui/audio_player.go18
-rwxr-xr-xtest_all_ui_elements.sh33
-rwxr-xr-xtest_bidirectional_translation.sh31
-rwxr-xr-xtest_image_prompt_persistence.sh31
-rwxr-xr-xtest_no_mixup.sh23
-rwxr-xr-xtest_phonetic_gui.sh21
-rwxr-xr-xtest_prompt_persistence.sh26
-rwxr-xr-xtest_scene_generation.sh20
-rwxr-xr-xtest_single_image.sh13
-rwxr-xr-xtest_translation_edit.sh17
-rwxr-xr-xtest_translation_fix.sh23
12 files changed, 88 insertions, 259 deletions
diff --git a/internal/gui/app.go b/internal/gui/app.go
index 46141d6..2caffe4 100644
--- a/internal/gui/app.go
+++ b/internal/gui/app.go
@@ -15,6 +15,7 @@ import (
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/storage"
+ "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/sashabaranov/go-openai"
@@ -192,9 +193,18 @@ func (a *Application) setupUI() {
a.window.Canvas().Unfocus()
}
- a.submitButton = widget.NewButton("Generate (g)", a.onSubmit)
- a.prevWordBtn = widget.NewButton("◀ Prev (←)", a.onPrevWord)
- a.nextWordBtn = widget.NewButton("Next (→) ▶", a.onNextWord)
+ // Create navigation buttons with tooltips
+ a.submitButton = widget.NewButtonWithIcon("", theme.ConfirmIcon(), a.onSubmit)
+ submitLabel := widget.NewLabelWithStyle("Generate (g)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ submitBtn := container.NewVBox(a.submitButton, submitLabel)
+
+ a.prevWordBtn = widget.NewButtonWithIcon("", theme.NavigateBackIcon(), a.onPrevWord)
+ prevLabel := widget.NewLabelWithStyle("Previous (←)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ prevBtn := container.NewVBox(a.prevWordBtn, prevLabel)
+
+ a.nextWordBtn = widget.NewButtonWithIcon("", theme.NavigateNextIcon(), a.onNextWord)
+ nextLabel := widget.NewLabelWithStyle("Next (→)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ nextBtn := container.NewVBox(a.nextWordBtn, nextLabel)
// Create a grid layout for inputs
inputGrid := container.New(layout.NewGridLayout(2),
@@ -204,8 +214,8 @@ func (a *Application) setupUI() {
inputSection := container.NewBorder(
nil, nil,
- a.prevWordBtn,
- container.NewHBox(a.submitButton, a.nextWordBtn),
+ prevBtn,
+ container.NewHBox(submitBtn, nextBtn),
inputGrid,
)
@@ -269,27 +279,44 @@ func (a *Application) setupUI() {
imageSection,
)
- // Create action buttons
- a.keepButton = widget.NewButton("New Word (n)", a.onKeepAndContinue)
- a.regenerateImageBtn = widget.NewButton("Regenerate Image (i)", a.onRegenerateImage)
- a.regenerateRandomImageBtn = widget.NewButton("Random Image (m)", a.onRegenerateRandomImage)
- a.regenerateAudioBtn = widget.NewButton("Regenerate Audio (a)", a.onRegenerateAudio)
- a.regenerateAllBtn = widget.NewButton("Regenerate All (r)", a.onRegenerateAll)
- a.deleteButton = widget.NewButton("Delete (d)", a.onDelete)
+ // Create action buttons with icons and tooltips
+ a.keepButton = widget.NewButtonWithIcon("", theme.DocumentCreateIcon(), a.onKeepAndContinue)
+ keepLabel := widget.NewLabelWithStyle("New Word (n)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ keepBtn := container.NewVBox(a.keepButton, keepLabel)
+
+ a.regenerateImageBtn = widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), a.onRegenerateImage)
+ imageLabel := widget.NewLabelWithStyle("Regenerate Image (i)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ regenerateImageBtn := container.NewVBox(a.regenerateImageBtn, imageLabel)
+
+ a.regenerateRandomImageBtn = widget.NewButtonWithIcon("", theme.MediaPhotoIcon(), a.onRegenerateRandomImage)
+ randomLabel := widget.NewLabelWithStyle("Random Image (m)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ regenerateRandomBtn := container.NewVBox(a.regenerateRandomImageBtn, randomLabel)
+
+ a.regenerateAudioBtn = widget.NewButtonWithIcon("", theme.MediaPlayIcon(), a.onRegenerateAudio)
+ audioLabel := widget.NewLabelWithStyle("Regenerate Audio (a)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ regenerateAudioBtn := container.NewVBox(a.regenerateAudioBtn, audioLabel)
+
+ a.regenerateAllBtn = widget.NewButtonWithIcon("", theme.ViewFullScreenIcon(), a.onRegenerateAll)
+ allLabel := widget.NewLabelWithStyle("Regenerate All (r)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ regenerateAllBtn := container.NewVBox(a.regenerateAllBtn, allLabel)
+
+ a.deleteButton = widget.NewButtonWithIcon("", theme.DeleteIcon(), a.onDelete)
a.deleteButton.Importance = widget.DangerImportance
+ deleteLabel := widget.NewLabelWithStyle("Delete (d)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true})
+ deleteBtn := container.NewVBox(a.deleteButton, deleteLabel)
// Initially disable action buttons
a.setActionButtonsEnabled(false)
actionSection := container.NewHBox(
- a.keepButton,
+ keepBtn,
layout.NewSpacer(),
- a.deleteButton,
+ deleteBtn,
widget.NewSeparator(),
- a.regenerateImageBtn,
- a.regenerateRandomImageBtn,
- a.regenerateAudioBtn,
- a.regenerateAllBtn,
+ regenerateImageBtn,
+ regenerateRandomBtn,
+ regenerateAudioBtn,
+ regenerateAllBtn,
)
// Create status section
@@ -344,6 +371,8 @@ func (a *Application) setupUI() {
// Run starts the GUI application
func (a *Application) Run() {
+ // Focus the Bulgarian word input on startup
+ a.window.Canvas().Focus(a.wordInput)
a.window.ShowAndRun()
}
@@ -1237,6 +1266,12 @@ func (a *Application) setupKeyboardShortcuts() {
return
}
+ // Handle Tab key for custom focus navigation
+ if ev.Name == fyne.KeyTab {
+ a.handleTabNavigation()
+ return
+ }
+
// Check if input field is focused
focused := a.window.Canvas().Focused()
isInputFocused := focused == a.wordInput || focused == a.imagePromptEntry || focused == a.translationEntry
@@ -1255,6 +1290,26 @@ func (a *Application) setupKeyboardShortcuts() {
})
}
+// handleTabNavigation manages custom Tab navigation order
+func (a *Application) handleTabNavigation() {
+ focused := a.window.Canvas().Focused()
+
+ switch focused {
+ case a.wordInput:
+ // From Bulgarian -> English
+ a.window.Canvas().Focus(a.translationEntry)
+ case a.translationEntry:
+ // From English -> Image prompt
+ a.window.Canvas().Focus(a.imagePromptEntry)
+ case a.imagePromptEntry:
+ // From Image prompt -> Bulgarian (cycle back)
+ a.window.Canvas().Focus(a.wordInput)
+ default:
+ // If nothing focused, start with Bulgarian
+ a.window.Canvas().Focus(a.wordInput)
+ }
+}
+
// handleShortcutKey handles the actual shortcut action
func (a *Application) handleShortcutKey(key fyne.KeyName) {
// Don't process if we're in delete confirmation mode
diff --git a/internal/gui/audio_player.go b/internal/gui/audio_player.go
index f36eddf..63428bd 100644
--- a/internal/gui/audio_player.go
+++ b/internal/gui/audio_player.go
@@ -9,6 +9,7 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
+ "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
@@ -39,10 +40,21 @@ func NewAudioPlayer() *AudioPlayer {
p.playButton.Disable()
p.stopButton.Disable()
- // Create container
- p.container = container.NewHBox(
+ // Create containers with tooltips
+ playContainer := container.NewVBox(
p.playButton,
+ widget.NewLabelWithStyle("Play (p)", fyne.TextAlignCenter, fyne.TextStyle{Italic: true}),
+ )
+
+ stopContainer := container.NewVBox(
p.stopButton,
+ widget.NewLabelWithStyle("Stop", fyne.TextAlignCenter, fyne.TextStyle{Italic: true}),
+ )
+
+ // Create main container
+ p.container = container.NewHBox(
+ playContainer,
+ stopContainer,
layout.NewSpacer(),
p.statusLabel,
)
@@ -164,7 +176,7 @@ func (p *AudioPlayer) startPlayback() error {
// Playback finished normally
fyne.Do(func() {
p.isPlaying = false
- p.playButton.SetText("▶ Play (p)")
+ p.playButton.SetIcon(theme.MediaPlayIcon())
p.stopButton.Disable()
p.statusLabel.SetText("Finished: " + filepath.Base(p.audioFile))
})
diff --git a/test_all_ui_elements.sh b/test_all_ui_elements.sh
deleted file mode 100755
index ddaa627..0000000
--- a/test_all_ui_elements.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-# Test script to verify all UI elements are preserved during rapid navigation
-
-echo "Starting totalrecall GUI to test all UI element preservation..."
-echo ""
-echo "Test procedure:"
-echo "1. Enter multiple words rapidly in different ways:"
-echo " - Word 1: Enter 'apple' in English field only"
-echo " - Word 2: Enter 'котка' in Bulgarian field only"
-echo " - Word 3: Enter 'куче' in Bulgarian with custom prompt 'brown dog running'"
-echo " - Word 4: Enter 'car' in English with custom prompt 'red sports car'"
-echo ""
-echo "2. While processing is happening, rapidly navigate using arrow keys"
-echo "3. Verify that for each word:"
-echo " - Bulgarian text stays correct"
-echo " - English translation stays correct"
-echo " - Custom image prompts are preserved"
-echo " - Phonetic information is displayed correctly"
-echo " - Audio files play the correct word"
-echo ""
-echo "4. Check the anki_cards folder for:"
-echo " - *_translation.txt files with correct translations"
-echo " - *_prompt.txt files with correct prompts"
-echo " - *_phonetic.txt files with correct phonetic info"
-echo " - Audio files that match the word names"
-echo ""
-echo "5. Restart the app and navigate through the words again"
-echo "6. Verify all data is correctly loaded from disk"
-echo ""
-echo "Press Ctrl+C to exit when testing is complete."
-echo ""
-
-./totalrecall gui \ No newline at end of file
diff --git a/test_bidirectional_translation.sh b/test_bidirectional_translation.sh
deleted file mode 100755
index 1a04bd8..0000000
--- a/test_bidirectional_translation.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# Test script to verify the bidirectional translation functionality
-
-echo "Starting totalrecall GUI with bidirectional translation feature..."
-echo ""
-echo "Test scenarios:"
-echo ""
-echo "1. Bulgarian -> English translation:"
-echo " - Enter 'ябълка' in Bulgarian field, leave English empty"
-echo " - Click 'Generate' or press 'g'"
-echo " - English translation 'apple' appears IMMEDIATELY in English field"
-echo " - Then audio and images are generated"
-echo ""
-echo "2. English -> Bulgarian translation:"
-echo " - Enter 'apple' in English field, leave Bulgarian empty"
-echo " - Click 'Generate' or press 'g'"
-echo " - Bulgarian translation 'ябълка' appears IMMEDIATELY in Bulgarian field"
-echo " - Then audio and images are generated"
-echo ""
-echo "3. Both fields provided (no translation):"
-echo " - Enter 'котка' in Bulgarian and 'cat' in English"
-echo " - Click 'Generate' - no translation should occur"
-echo ""
-echo "4. Edit translations:"
-echo " - You can manually edit the English translation at any time"
-echo " - Changes are saved automatically"
-echo ""
-echo "Press Ctrl+C to exit when testing is complete."
-echo ""
-
-./totalrecall gui \ No newline at end of file
diff --git a/test_image_prompt_persistence.sh b/test_image_prompt_persistence.sh
deleted file mode 100755
index adc311a..0000000
--- a/test_image_prompt_persistence.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# Test script to verify image prompt persistence functionality
-
-echo "Testing image prompt persistence in totalrecall GUI..."
-echo ""
-echo "Test scenarios:"
-echo ""
-echo "1. Create card with custom prompt:"
-echo " - Enter 'котка' in Bulgarian field"
-echo " - Enter custom prompt: 'cute fluffy cat playing with yarn'"
-echo " - Generate the card"
-echo " - The prompt is automatically saved"
-echo ""
-echo "2. Navigate away and back:"
-echo " - Use navigation arrows to go to another word"
-echo " - Navigate back to 'котка'"
-echo " - The custom prompt should be restored"
-echo ""
-echo "3. Regenerate image:"
-echo " - Click 'Regenerate Image'"
-echo " - The saved prompt will be used automatically"
-echo ""
-echo "4. Edit and save prompt:"
-echo " - Modify the prompt text"
-echo " - Changes are saved automatically"
-echo " - Regenerate to see the new prompt in action"
-echo ""
-echo "Press Ctrl+C to exit when testing is complete."
-echo ""
-
-./totalrecall gui \ No newline at end of file
diff --git a/test_no_mixup.sh b/test_no_mixup.sh
deleted file mode 100755
index 863977d..0000000
--- a/test_no_mixup.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# Test script to verify that rapid word entry doesn't cause mix-ups
-
-echo "Starting totalrecall GUI to test rapid word entry..."
-echo ""
-echo "Test procedure:"
-echo "1. Enter a word (e.g., 'ябълка') and click Generate"
-echo "2. While it's still processing, immediately enter a new word (e.g., 'котка')"
-echo "3. Click Generate for the second word"
-echo "4. Verify that:"
-echo " - The first word's image/audio appears correctly when it completes"
-echo " - The second word's image/audio appears correctly when it completes"
-echo " - No mix-ups occur between the two words"
-echo "5. Check the anki_cards folder to ensure files are correctly named"
-echo ""
-echo "Additional tests:"
-echo "- Try entering 'rocket launcher' in English, then quickly enter another word"
-echo "- Verify the translation doesn't get mixed up"
-echo ""
-echo "Press Ctrl+C to exit when testing is complete."
-echo ""
-
-./totalrecall gui \ No newline at end of file
diff --git a/test_phonetic_gui.sh b/test_phonetic_gui.sh
deleted file mode 100755
index 0ceaf6b..0000000
--- a/test_phonetic_gui.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-# Test script for the phonetic information GUI feature
-
-echo "Testing TotalRecall GUI with phonetic information feature..."
-echo ""
-echo "Features to test:"
-echo "1. Enter Bulgarian words like: ябълка (apple), котка (cat), куче (dog)"
-echo "2. Phonetic info shows detailed IPA with pronunciation examples for EACH letter"
-echo "3. Examples compare to English sounds (e.g., '/a/ like in father')"
-echo "4. Phonetic info is saved automatically and persists after restart"
-echo "5. Use arrow keys or prev/next buttons to navigate between cards"
-echo "6. Info fetches concurrently with audio/image for faster processing"
-echo ""
-echo "The phonetic text area is located between the image section and audio controls."
-echo ""
-echo "Press Enter to start the GUI..."
-read
-
-# Run the GUI
-./totalrecall gui \ No newline at end of file
diff --git a/test_prompt_persistence.sh b/test_prompt_persistence.sh
deleted file mode 100755
index 33c4b7e..0000000
--- a/test_prompt_persistence.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-# Test script to verify that image prompts are preserved during rapid navigation
-
-echo "Starting totalrecall GUI to test prompt persistence..."
-echo ""
-echo "Test procedure:"
-echo "1. Enter multiple words quickly with custom prompts:"
-echo " - Word 1: 'ябълка' with prompt 'red apple on wooden table'"
-echo " - Word 2: 'котка' with prompt 'orange cat sleeping on sofa'"
-echo " - Word 3: 'куче' with prompt 'golden retriever playing in park'"
-echo ""
-echo "2. While images are still generating, navigate rapidly using arrow keys"
-echo "3. Verify that:"
-echo " - Each word retains its correct custom prompt"
-echo " - Prompts don't get mixed up between words"
-echo " - Prompts are saved to disk (*_prompt.txt files)"
-echo ""
-echo "4. After all processing completes, navigate through words again"
-echo "5. Verify prompts are correctly loaded from disk"
-echo ""
-echo "Check the anki_cards folder for *_prompt.txt files"
-echo ""
-echo "Press Ctrl+C to exit when testing is complete."
-echo ""
-
-./totalrecall gui \ No newline at end of file
diff --git a/test_scene_generation.sh b/test_scene_generation.sh
deleted file mode 100755
index 0355167..0000000
--- a/test_scene_generation.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-# Test scene generation with Bulgarian words
-echo "Testing scene generation for Bulgarian flashcards..."
-
-# Test words
-words=("ябълка" "котка" "куче" "хляб" "вода" "книга")
-
-for word in "${words[@]}"; do
- echo ""
- echo "===================="
- echo "Testing word: $word"
- echo "===================="
- go run ./cmd/totalrecall "$word" --provider openai
- echo ""
- echo "Press Enter to continue to next word..."
- read
-done
-
-echo "Scene generation test complete!" \ No newline at end of file
diff --git a/test_single_image.sh b/test_single_image.sh
deleted file mode 100755
index 3dde0de..0000000
--- a/test_single_image.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-# Test script to verify single image functionality
-
-echo "Building totalrecall..."
-go build -o totalrecall ./cmd/totalrecall || exit 1
-
-echo "Testing CLI mode with a single word..."
-./totalrecall "котка" || exit 1
-
-echo "Checking generated files..."
-ls -la output/котка*
-
-echo "Test completed successfully!" \ No newline at end of file
diff --git a/test_translation_edit.sh b/test_translation_edit.sh
deleted file mode 100755
index 79b501a..0000000
--- a/test_translation_edit.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-# Test script to verify the translation editing functionality
-
-echo "Starting totalrecall GUI with translation editing feature..."
-echo ""
-echo "Test instructions:"
-echo "1. Enter a Bulgarian word (e.g., 'ябълка')"
-echo "2. Click 'Generate' or press 'g'"
-echo "3. Wait for translation to appear"
-echo "4. Try editing the translation in the text field"
-echo "5. Navigate away and back to verify the translation was saved"
-echo "6. The edited translation should persist"
-echo ""
-echo "Press Ctrl+C to exit when testing is complete."
-echo ""
-
-./totalrecall gui \ No newline at end of file
diff --git a/test_translation_fix.sh b/test_translation_fix.sh
deleted file mode 100755
index 8be4aeb..0000000
--- a/test_translation_fix.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# Test script to verify the translation fix
-
-echo "Testing totalrecall translation fix..."
-echo "======================================="
-echo ""
-echo "This test verifies that when a Bulgarian word is translated to English,"
-echo "the English translation is used for image generation without re-translating."
-echo ""
-echo "To test manually:"
-echo "1. Run: ./totalrecall"
-echo "2. Enter a Bulgarian word (e.g., ябълка)"
-echo "3. Wait for it to be translated to English (e.g., apple)"
-echo "4. Optionally edit the English translation"
-echo "5. Click Generate or press Enter"
-echo "6. Watch the console output - it should show:"
-echo " 'Using provided translation: ябълка -> apple'"
-echo " instead of translating again"
-echo ""
-echo "Expected behavior:"
-echo "- The image generation uses the translation shown in the UI"
-echo "- No additional translation happens during image generation"
-echo "- Console shows 'Using provided translation' message" \ No newline at end of file