summaryrefslogtreecommitdiff
path: root/internal/gui
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-21 23:22:38 +0300
committerPaul Buetow <paul@buetow.org>2025-07-21 23:22:38 +0300
commitbc1c6e76d5a6ef2623d26d277473c459dd699f81 (patch)
tree3bc0c7b4b730d50fb15ae38458037fe2f8ac4b2f /internal/gui
parenta43d503533f301db43af412167fda26364542e27 (diff)
feat: Enhanced bulk import, archive functionality, and export improvements
## Bulk Import Enhancements - Added support for three flexible batch file formats: - `BULGARIAN = ENGLISH` - Both provided, no translation needed - `= ENGLISH` - Only English provided, auto-translated to Bulgarian - `BULGARIAN` - Only Bulgarian provided, auto-translated to English - Implemented smart file checking to skip already processed words - Check all required files (word.txt, translation.txt, phonetic.txt, audio/image files and their attribution/metadata) - Added batch processing summary with statistics ## Archive Functionality - Renamed --clear flag to --archive for clarity - Archive cards directory to ~/.local/state/totalrecall/archive/cards-TIMESTAMP - Added archive button to GUI toolbar with folder icon - Archive confirmation dialog supports keyboard shortcuts (y/n/c/ESC) ## Export Improvements - Anki exports now show full file path in output - Changed default export location to home directory (~) for both CLI and GUI - Auto-adjust image size to 1024x1024 when DALL-E 3 is selected ## Other Improvements - Added TranslateEnglishToBulgarian method for reverse translation - Enhanced batch processing with better error handling and progress reporting - Improved file integrity checking for complete word processing 🤖 Generated with [opencode](https://opencode.ai) Co-Authored-By: opencode <noreply@opencode.ai>
Diffstat (limited to 'internal/gui')
-rw-r--r--internal/gui/app.go122
1 files changed, 119 insertions, 3 deletions
diff --git a/internal/gui/app.go b/internal/gui/app.go
index ef0ee43..cd4b711 100644
--- a/internal/gui/app.go
+++ b/internal/gui/app.go
@@ -23,6 +23,7 @@ import (
"codeberg.org/snonux/totalrecall/internal"
"codeberg.org/snonux/totalrecall/internal/anki"
+ "codeberg.org/snonux/totalrecall/internal/archive"
"codeberg.org/snonux/totalrecall/internal/audio"
)
@@ -345,8 +346,9 @@ func (a *Application) setupUI() {
// But keep delete button enabled for cancelling operations
a.deleteButton.Enable()
- // Create export and help buttons for toolbar
+ // Create export, archive and help buttons for toolbar
exportButton := ttwidget.NewButtonWithIcon("", theme.UploadIcon(), a.onExportToAnki)
+ archiveButton := ttwidget.NewButtonWithIcon("", theme.FolderOpenIcon(), a.onArchive)
helpButton := ttwidget.NewButtonWithIcon("", theme.HelpIcon(), a.onShowHotkeys)
// Create toolbar with navigation buttons first, then action buttons
@@ -363,6 +365,7 @@ func (a *Application) setupUI() {
a.regenerateAllBtn,
widget.NewSeparator(),
exportButton,
+ archiveButton,
helpButton,
)
@@ -400,13 +403,16 @@ func (a *Application) setupUI() {
// Now that tooltip layer is created, set all tooltips
a.setupTooltips()
- // Set tooltips for export and help buttons with a delay
+ // Set tooltips for export, archive and help buttons with a delay
go func() {
time.Sleep(500 * time.Millisecond)
fyne.Do(func() {
if exportButton != nil {
exportButton.SetToolTip("Export to Anki (x)")
}
+ if archiveButton != nil {
+ archiveButton.SetToolTip("Archive all cards")
+ }
if helpButton != nil {
helpButton.SetToolTip("Show hotkeys (?)")
}
@@ -1034,7 +1040,7 @@ func (a *Application) onExportToAnki() {
// Export directory selection
homeDir, _ := os.UserHomeDir()
- defaultExportDir := filepath.Join(homeDir, "Downloads")
+ defaultExportDir := homeDir // Changed from Downloads to home directory
selectedDir := defaultExportDir
dirLabel := widget.NewLabel(selectedDir)
@@ -1199,6 +1205,110 @@ func (a *Application) onExportToAnki() {
customDialog.Show()
}
+// onArchive archives the current cards directory
+func (a *Application) onArchive() {
+ // Function to perform the archive
+ performArchive := func() {
+ // Get the cards directory path
+ home, _ := os.UserHomeDir()
+ cardsDir := filepath.Join(home, ".local", "state", "totalrecall", "cards")
+
+ // Archive the cards
+ if err := archive.ArchiveCards(cardsDir); err != nil {
+ dialog.ShowError(err, a.window)
+ return
+ }
+
+ // Clear the saved cards list
+ a.mu.Lock()
+ a.savedCards = []anki.Card{}
+ a.existingWords = []string{}
+ a.mu.Unlock()
+
+ // Update status
+ a.updateStatus("Cards archived successfully")
+
+ // Refresh the current word display
+ a.scanExistingWords()
+ if a.currentWord != "" {
+ a.loadExistingFiles(a.currentWord)
+ }
+ }
+
+ // Create confirmation dialog
+ confirmDialog := dialog.NewConfirm("Archive Cards",
+ "Are you sure you want to archive all existing cards?\n\nThis will move the cards directory to:\n~/.local/state/totalrecall/archive/cards-TIMESTAMP",
+ func(confirmed bool) {
+ if confirmed {
+ performArchive()
+ }
+ },
+ a.window,
+ )
+
+ // Track if we're in archive confirmation mode
+ archiveConfirming := true
+
+ // Save original key handlers
+ oldKeyHandler := a.window.Canvas().OnTypedKey()
+ oldRuneHandler := a.window.Canvas().OnTypedRune()
+
+ // Handle both Latin and Cyrillic keys
+ a.window.Canvas().SetOnTypedRune(func(r rune) {
+ if archiveConfirming {
+ switch r {
+ case 'y', 'Y', 'ъ', 'Ъ':
+ confirmDialog.Hide()
+ archiveConfirming = false
+ performArchive()
+ // Restore original handlers
+ a.window.Canvas().SetOnTypedKey(oldKeyHandler)
+ a.window.Canvas().SetOnTypedRune(oldRuneHandler)
+ case 'n', 'N', 'н', 'Н', 'c', 'C', 'ц', 'Ц':
+ confirmDialog.Hide()
+ archiveConfirming = false
+ // Restore original handlers
+ a.window.Canvas().SetOnTypedKey(oldKeyHandler)
+ a.window.Canvas().SetOnTypedRune(oldRuneHandler)
+ }
+ } else if oldRuneHandler != nil {
+ oldRuneHandler(r)
+ }
+ })
+
+ // Handle special keys
+ a.window.Canvas().SetOnTypedKey(func(ev *fyne.KeyEvent) {
+ if archiveConfirming {
+ switch ev.Name {
+ case fyne.KeyY:
+ confirmDialog.Hide()
+ archiveConfirming = false
+ performArchive()
+ // Restore original handlers
+ a.window.Canvas().SetOnTypedKey(oldKeyHandler)
+ a.window.Canvas().SetOnTypedRune(oldRuneHandler)
+ case fyne.KeyN, fyne.KeyC, fyne.KeyEscape:
+ confirmDialog.Hide()
+ archiveConfirming = false
+ // Restore original handlers
+ a.window.Canvas().SetOnTypedKey(oldKeyHandler)
+ a.window.Canvas().SetOnTypedRune(oldRuneHandler)
+ }
+ } else if oldKeyHandler != nil {
+ oldKeyHandler(ev)
+ }
+ })
+
+ // Set up dialog close handler to restore key handlers
+ confirmDialog.SetOnClosed(func() {
+ archiveConfirming = false
+ a.window.Canvas().SetOnTypedKey(oldKeyHandler)
+ a.window.Canvas().SetOnTypedRune(oldRuneHandler)
+ })
+
+ confirmDialog.Show()
+}
+
// onShowHotkeys displays a dialog with all available keyboard shortcuts
func (a *Application) onShowHotkeys() {
hotkeys := `[Project Page: https://codeberg.org/snonux/totalrecall](https://codeberg.org/snonux/totalrecall)
@@ -1237,6 +1347,12 @@ func (a *Application) onShowHotkeys() {
**c/ц** Close dialog
**q/ч** Quit application
+## Dialogs
+**y/ъ** Confirm action
+**n/н** Cancel action
+**c/ц** Cancel action
+**Esc** Cancel action
+
---
*All hotkeys work with both Latin and Cyrillic keyboards*