From 77538381c28e4de8fa7d3f3731412c97699bb889 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 19 Jul 2025 16:37:04 +0300 Subject: feat: add app icon and change default output directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add custom app icon with memory/brain theme - Icon now displays in GNOME app menu, window title bar, and process list - Change default output directory to ~/.local/state/totalrecall/ - Make output directory configurable via CLI flag, config file, or env var - Add desktop entry file for GNOME integration - Add install script for easy icon installation - Update README with icon display and default directory information - Bump version to 0.5.1 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .gitignore | 5 +++ README.md | 52 ++++++++++++++++++++++++++++-- assets/icons/totalrecall.svg | 66 +++++++++++++++++++++++++++++++++++++++ assets/icons/totalrecall_128.png | Bin 0 -> 26276 bytes assets/icons/totalrecall_16.png | Bin 0 -> 1700 bytes assets/icons/totalrecall_256.png | Bin 0 -> 62217 bytes assets/icons/totalrecall_32.png | Bin 0 -> 4560 bytes assets/icons/totalrecall_48.png | Bin 0 -> 7238 bytes assets/icons/totalrecall_512.png | Bin 0 -> 40153 bytes assets/icons/totalrecall_64.png | Bin 0 -> 10653 bytes cmd/totalrecall/main.go | 11 ++++++- install-icon.sh | 66 +++++++++++++++++++++++++++++++++++++++ internal/gui/app.go | 6 +++- internal/gui/icon.go | 17 ++++++++++ internal/gui/totalrecall_256.png | Bin 0 -> 62217 bytes internal/version.go | 2 +- totalrecall.desktop | 13 ++++++++ 17 files changed, 232 insertions(+), 6 deletions(-) create mode 100644 assets/icons/totalrecall.svg create mode 100644 assets/icons/totalrecall_128.png create mode 100644 assets/icons/totalrecall_16.png create mode 100644 assets/icons/totalrecall_256.png create mode 100644 assets/icons/totalrecall_32.png create mode 100644 assets/icons/totalrecall_48.png create mode 100644 assets/icons/totalrecall_512.png create mode 100644 assets/icons/totalrecall_64.png create mode 100755 install-icon.sh create mode 100644 internal/gui/icon.go create mode 100644 internal/gui/totalrecall_256.png create mode 100644 totalrecall.desktop diff --git a/.gitignore b/.gitignore index 20e144e..4a70ff3 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,8 @@ anki_cards # Configuration with API keys .totalrecall.yaml .image_cache/ + +# Test output directories +test_output/ +test_output2/ +test_phonetic/ diff --git a/README.md b/README.md index 24bfbf3..828d991 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # totalrecall - Bulgarian Anki Flashcard Generator +

+ TotalRecall Icon +

+ `totalrecall` is a versatile tool for generating Anki flashcard materials from Bulgarian words. It offers both a command-line interface (CLI) and a graphical user interface (GUI) for creating audio pronunciation files and AI-generated images. It has mainly been vibe coded using Claude Code CLI. @@ -22,6 +26,7 @@ It has mainly been vibe coded using Claude Code CLI. - Anki-compatible CSV export with translations - Random voice variants and speech speed - Audio caching to save API costs +- **Default output directory**: `~/.local/state/totalrecall/` (configurable) ## Installation @@ -42,12 +47,45 @@ cd totalrecall go build -o totalrecall ./cmd/totalrecall ``` -Or install directly: +### Installing to Go Bin Directory + +Using Task (recommended): +```bash +cd totalrecall +task install +``` + +Or using go install directly: +```bash +cd totalrecall +go install ./cmd/totalrecall +``` +Or install from remote repository: ```bash go install codeberg.org/snonux/totalrecall/cmd/totalrecall@latest ``` +This will install the binary to `~/go/bin/totalrecall`, which should be in your PATH. + +### Desktop Icon Installation (GNOME/Fedora) + +TotalRecall includes a desktop icon for GNOME integration. To install: + +**For current user only:** +```bash +cd totalrecall +./install-icon.sh +``` + +**System-wide installation:** +```bash +cd totalrecall +sudo ./install-icon.sh +``` + +After installation, you may need to log out and log back in for the icon to appear in GNOME's application menu. The icon will show up as "TotalRecall" in the Education category. + ## Quick Start **Note:** By default, totalrecall uses OpenAI for both audio and images. Make sure to set your OpenAI API key: @@ -92,7 +130,13 @@ Launch the interactive graphical interface: totalrecall --gui ``` -Then use keyboard shortcuts or buttons to generate and manage flashcards interactively. +The GUI is best navigated using keyboard shortcuts for efficient workflow. Press **`h`** at any time to display a complete list of all available keyboard shortcuts. + +Key features: +- Fast keyboard-driven interface +- Real-time audio playback +- Batch processing support +- Visual feedback for all operations ## Configuration @@ -123,7 +167,7 @@ image: openai_style: "natural" # Style: natural or vivid (dall-e-3 only) output: - directory: ./anki_cards + directory: ~/.local/state/totalrecall # Default location (can be overridden) naming: "{word}_{type}" ``` @@ -174,6 +218,8 @@ When translations are provided, they are used directly without calling the trans ### Output Files +By default, all files are saved to `~/.local/state/totalrecall/`. You can override this with the `-o` flag or the `output.directory` config option. + For each word, the tool generates: - `word.mp3` - Audio pronunciation (random voice) - `word_translation.txt` - English translation diff --git a/assets/icons/totalrecall.svg b/assets/icons/totalrecall.svg new file mode 100644 index 0000000..145018e --- /dev/null +++ b/assets/icons/totalrecall.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/icons/totalrecall_128.png b/assets/icons/totalrecall_128.png new file mode 100644 index 0000000..cce572f Binary files /dev/null and b/assets/icons/totalrecall_128.png differ diff --git a/assets/icons/totalrecall_16.png b/assets/icons/totalrecall_16.png new file mode 100644 index 0000000..381f124 Binary files /dev/null and b/assets/icons/totalrecall_16.png differ diff --git a/assets/icons/totalrecall_256.png b/assets/icons/totalrecall_256.png new file mode 100644 index 0000000..1d5c297 Binary files /dev/null and b/assets/icons/totalrecall_256.png differ diff --git a/assets/icons/totalrecall_32.png b/assets/icons/totalrecall_32.png new file mode 100644 index 0000000..1611629 Binary files /dev/null and b/assets/icons/totalrecall_32.png differ diff --git a/assets/icons/totalrecall_48.png b/assets/icons/totalrecall_48.png new file mode 100644 index 0000000..e33f4ec Binary files /dev/null and b/assets/icons/totalrecall_48.png differ diff --git a/assets/icons/totalrecall_512.png b/assets/icons/totalrecall_512.png new file mode 100644 index 0000000..724aaf3 Binary files /dev/null and b/assets/icons/totalrecall_512.png differ diff --git a/assets/icons/totalrecall_64.png b/assets/icons/totalrecall_64.png new file mode 100644 index 0000000..824dc55 Binary files /dev/null and b/assets/icons/totalrecall_64.png differ diff --git a/cmd/totalrecall/main.go b/cmd/totalrecall/main.go index 7fffbaf..f8039a8 100644 --- a/cmd/totalrecall/main.go +++ b/cmd/totalrecall/main.go @@ -73,11 +73,15 @@ func init() { // Initialize random number generator rand.Seed(time.Now().UnixNano()) + // Set default output directory + home, _ := os.UserHomeDir() + defaultOutputDir := filepath.Join(home, ".local", "state", "totalrecall") + // Global flags rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.totalrecall.yaml)") // Local flags - rootCmd.Flags().StringVarP(&outputDir, "output", "o", "./anki_cards", "Output directory") + rootCmd.Flags().StringVarP(&outputDir, "output", "o", defaultOutputDir, "Output directory") rootCmd.Flags().StringVarP(&audioFormat, "format", "f", "mp3", "Audio format (wav or mp3)") rootCmd.Flags().StringVar(&imageAPI, "image-api", "openai", "Image source (only openai supported)") rootCmd.Flags().StringVar(&batchFile, "batch", "", "Process words from file (one per line)") @@ -151,6 +155,11 @@ func initConfig() { } func runCommand(cmd *cobra.Command, args []string) error { + // Check if output directory was set in config file + if !cmd.Flags().Changed("output") && viper.IsSet("output.directory") { + outputDir = viper.GetString("output.directory") + } + // Handle --list-models flag if listModels { return listAvailableModels() diff --git a/install-icon.sh b/install-icon.sh new file mode 100755 index 0000000..dd5c224 --- /dev/null +++ b/install-icon.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# Script to install TotalRecall icon for GNOME on Fedora Linux +# Run with sudo for system-wide installation + +set -e + +# Check if running as root for system-wide install +if [[ $EUID -eq 0 ]]; then + echo "Installing TotalRecall icon system-wide..." + ICON_BASE="/usr/share/icons/hicolor" + APP_DIR="/usr/share/applications" + BINARY_PATH="/usr/local/bin/totalrecall" +else + echo "Installing TotalRecall icon for current user..." + ICON_BASE="$HOME/.local/share/icons/hicolor" + APP_DIR="$HOME/.local/share/applications" + BINARY_PATH="$HOME/go/bin/totalrecall" +fi + +# Create directories +mkdir -p "$ICON_BASE"/{16x16,32x32,48x48,64x64,128x128,256x256,512x512}/apps +mkdir -p "$APP_DIR" + +# Copy icons +cp assets/icons/totalrecall_16.png "$ICON_BASE/16x16/apps/totalrecall.png" +cp assets/icons/totalrecall_32.png "$ICON_BASE/32x32/apps/totalrecall.png" +cp assets/icons/totalrecall_48.png "$ICON_BASE/48x48/apps/totalrecall.png" +cp assets/icons/totalrecall_64.png "$ICON_BASE/64x64/apps/totalrecall.png" +cp assets/icons/totalrecall_128.png "$ICON_BASE/128x128/apps/totalrecall.png" +cp assets/icons/totalrecall_256.png "$ICON_BASE/256x256/apps/totalrecall.png" +cp assets/icons/totalrecall_512.png "$ICON_BASE/512x512/apps/totalrecall.png" + +# Copy scalable icon +mkdir -p "$ICON_BASE/scalable/apps" +cp assets/icons/totalrecall.svg "$ICON_BASE/scalable/apps/totalrecall.svg" + +# Copy and update desktop file with correct binary path +# First check if totalrecall is in standard locations +if command -v totalrecall &> /dev/null; then + TOTALRECALL_PATH=$(command -v totalrecall) +elif [[ -x "$HOME/go/bin/totalrecall" ]]; then + TOTALRECALL_PATH="$HOME/go/bin/totalrecall" +elif [[ -x "/usr/local/bin/totalrecall" ]]; then + TOTALRECALL_PATH="/usr/local/bin/totalrecall" +elif [[ -x "/usr/bin/totalrecall" ]]; then + TOTALRECALL_PATH="/usr/bin/totalrecall" +else + echo "Warning: totalrecall binary not found in standard locations" + echo "Please install totalrecall first with 'task install' or 'go install ./cmd/totalrecall'" + TOTALRECALL_PATH="totalrecall" +fi + +# Create desktop file with proper exec path +sed "s|Exec=totalrecall|Exec=$TOTALRECALL_PATH|g" totalrecall.desktop > "$APP_DIR/totalrecall.desktop" + +# Update caches +if command -v gtk-update-icon-cache &> /dev/null; then + gtk-update-icon-cache -f -t "$ICON_BASE" 2>/dev/null || true +fi + +if command -v update-desktop-database &> /dev/null; then + update-desktop-database "$APP_DIR" 2>/dev/null || true +fi + +echo "TotalRecall icon installed successfully!" +echo "You may need to log out and log back in to see the icon in GNOME." \ No newline at end of file diff --git a/internal/gui/app.go b/internal/gui/app.go index 31d2460..2226eb1 100644 --- a/internal/gui/app.go +++ b/internal/gui/app.go @@ -112,8 +112,11 @@ func New(config *Config) *Application { ctx, cancel := context.WithCancel(context.Background()) + myApp := app.New() + myApp.SetIcon(GetAppIcon()) + app := &Application{ - app: app.New(), + app: myApp, config: config, ctx: ctx, cancel: cancel, @@ -152,6 +155,7 @@ func New(config *Config) *Application { // setupUI creates the main user interface func (a *Application) setupUI() { a.window = a.app.NewWindow(fmt.Sprintf("TotalRecall v%s - Bulgarian Flashcard Generator", internal.Version)) + a.window.SetIcon(GetAppIcon()) a.window.Resize(fyne.NewSize(800, 700)) // Create input section with navigation diff --git a/internal/gui/icon.go b/internal/gui/icon.go new file mode 100644 index 0000000..f778225 --- /dev/null +++ b/internal/gui/icon.go @@ -0,0 +1,17 @@ +package gui + +import ( + _ "embed" + "fyne.io/fyne/v2" +) + +//go:embed totalrecall_256.png +var iconData []byte + +// GetAppIcon returns the application icon as a Fyne resource +func GetAppIcon() fyne.Resource { + return &fyne.StaticResource{ + StaticName: "totalrecall.png", + StaticContent: iconData, + } +} \ No newline at end of file diff --git a/internal/gui/totalrecall_256.png b/internal/gui/totalrecall_256.png new file mode 100644 index 0000000..1d5c297 Binary files /dev/null and b/internal/gui/totalrecall_256.png differ diff --git a/internal/version.go b/internal/version.go index c658e16..360eeb8 100644 --- a/internal/version.go +++ b/internal/version.go @@ -1,3 +1,3 @@ package internal -const Version = "0.5.0" +const Version = "0.5.1" diff --git a/totalrecall.desktop b/totalrecall.desktop new file mode 100644 index 0000000..41be16e --- /dev/null +++ b/totalrecall.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=TotalRecall +GenericName=Bulgarian Flashcard Generator +Comment=Generate Anki flashcard materials from Bulgarian words +Exec=totalrecall --gui +Icon=totalrecall +Terminal=false +Categories=Education;Languages; +Keywords=bulgarian;flashcards;anki;language;learning; +StartupNotify=true +StartupWMClass=totalrecall \ No newline at end of file -- cgit v1.2.3