diff --git a/internal/queue/queue.go b/internal/queue/queue.go index dcfcd85..fd2d46b 100644 --- a/internal/queue/queue.go +++ b/internal/queue/queue.go @@ -378,6 +378,15 @@ func (q *Queue) Clear() { q.notifyChange() } +// ClearAll removes all jobs from the queue +func (q *Queue) ClearAll() { + q.mu.Lock() + defer q.mu.Unlock() + + q.jobs = make([]*Job, 0) + q.notifyChange() +} + // generateID generates a unique ID for a job func generateID() string { return fmt.Sprintf("job-%d", time.Now().UnixNano()) diff --git a/internal/ui/queueview.go b/internal/ui/queueview.go index 634fb8a..e05fb21 100644 --- a/internal/ui/queueview.go +++ b/internal/ui/queueview.go @@ -21,6 +21,7 @@ func BuildQueueView( onCancel func(string), onRemove func(string), onClear func(), + onClearAll func(), titleColor, bgColor, textColor color.Color, ) fyne.CanvasObject { // Header @@ -29,12 +30,18 @@ func BuildQueueView( title.TextSize = 24 backBtn := widget.NewButton("← Back", onBack) + backBtn.Importance = widget.LowImportance + clearBtn := widget.NewButton("Clear Completed", onClear) + clearBtn.Importance = widget.LowImportance + + clearAllBtn := widget.NewButton("Clear All", onClearAll) + clearAllBtn.Importance = widget.DangerImportance header := container.NewBorder( nil, nil, backBtn, - clearBtn, + container.NewHBox(clearBtn, clearAllBtn), container.NewCenter(title), ) diff --git a/main.go b/main.go index ef8db58..3484bc7 100644 --- a/main.go +++ b/main.go @@ -151,31 +151,30 @@ func (c convertConfig) CoverLabel() string { } type appState struct { - window fyne.Window - active string - initComplete bool // True after initial UI setup completes - source *videoSource - loadedVideos []*videoSource // Multiple loaded videos for navigation - currentIndex int // Current video index in loadedVideos - anim *previewAnimator - convert convertConfig - currentFrame string - player player.Controller - playerReady bool - playerVolume float64 - playerMuted bool - lastVolume float64 - playerPaused bool - playerPos float64 - playerLast time.Time - progressQuit chan struct{} - convertCancel context.CancelFunc - playerSurf *playerSurface - convertBusy bool - convertStatus string - playSess *playSession - jobQueue *queue.Queue - statsBar *ui.ConversionStatsBar + window fyne.Window + active string + source *videoSource + loadedVideos []*videoSource // Multiple loaded videos for navigation + currentIndex int // Current video index in loadedVideos + anim *previewAnimator + convert convertConfig + currentFrame string + player player.Controller + playerReady bool + playerVolume float64 + playerMuted bool + lastVolume float64 + playerPaused bool + playerPos float64 + playerLast time.Time + progressQuit chan struct{} + convertCancel context.CancelFunc + playerSurf *playerSurface + convertBusy bool + convertStatus string + playSess *playSession + jobQueue *queue.Queue + statsBar *ui.ConversionStatsBar } func (s *appState) stopPreview() { @@ -425,6 +424,10 @@ func (s *appState) showQueue() { s.jobQueue.Clear() s.showQueue() // Refresh }, + func() { // onClearAll + s.jobQueue.ClearAll() + s.showQueue() // Refresh + }, utils.MustHex("#4CE870"), // titleColor gridColor, // bgColor textColor, // textColor @@ -1082,39 +1085,27 @@ func runGUI() { // Start queue processing (but paused by default) state.jobQueue.Start() - // Set callback - queue changes are triggered by job processor goroutine - state.jobQueue.SetChangeCallback(func() { - // Skip updates during initialization - if !state.initComplete { - return - } - - // Marshal UI updates to main thread - app := fyne.CurrentApp() - if app == nil || app.Driver() == nil { - return - } - - app.Driver().DoFromGoroutine(func() { - // Update stats bar - state.updateStatsBar() - - // Refresh UI when queue changes and we're on main menu - if state.active == "" { - state.showMainMenu() - } - }, false) - }) - - // Mark initialization as complete - state.initComplete = true - defer state.shutdown() w.SetOnDropped(func(pos fyne.Position, items []fyne.URI) { state.handleDrop(pos, items) }) state.showMainMenu() logging.Debug(logging.CatUI, "main menu rendered with %d modules", len(modulesList)) + + // Start stats bar update loop on a timer + go func() { + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + for range ticker.C { + app := fyne.CurrentApp() + if app != nil && app.Driver() != nil { + app.Driver().DoFromGoroutine(func() { + state.updateStatsBar() + }, false) + } + } + }() + w.ShowAndRun() }