From ac86864c7286bf2a887c9976c313dcd9dd1225c7 Mon Sep 17 00:00:00 2001 From: NeilClack Date: Thu, 18 Jun 2026 22:43:47 -0500 Subject: [PATCH] Add downloading message to home screen. Download files in the background and keep track of progress. --- internal/application/application.go | 3 +- internal/download/Download.go | 9 +-- internal/page/home.go | 108 ++++++++++++++++++---------- 3 files changed, 78 insertions(+), 42 deletions(-) diff --git a/internal/application/application.go b/internal/application/application.go index 52e0475..cee6e72 100644 --- a/internal/application/application.go +++ b/internal/application/application.go @@ -154,7 +154,8 @@ func Run() { app.initializeManagers() app.initializeAudio() - downloadProgressChan := make(chan download.DownloadStatus) + // Create a buffered channel so log writes don't slow down downloads. + downloadProgressChan := make(chan download.DownloadStatus, 1000) app.PageRouter = page.NewRouter(page.PageCtx{ CfgPtr: app.Config.Load(), diff --git a/internal/download/Download.go b/internal/download/Download.go index 6a50944..5e704c6 100644 --- a/internal/download/Download.go +++ b/internal/download/Download.go @@ -30,6 +30,7 @@ func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, // First, calculate the total size of files that need to be downloaded totalSize := int64(0) filesToDownload := []string{} + totalDownloaded := int64(0) for _, filename := range filenames { destPath := filepath.Join(destDir, filename) @@ -62,13 +63,15 @@ func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, // Append it to the list to download filesToDownload = append(filesToDownload, filename) - // And increase the total bytes to download - totalSize += resp.ContentLength } else if err != nil { logger.Error("unknown error: %v", err) } else { logger.Error("File %s exists, skipping...", filename) + totalDownloaded += fileStat.Size() } + // Calculate the total of ALL files to give the illusion of + // "picking up where you left off" to the user + totalSize += resp.ContentLength resp.Body.Close() } @@ -79,8 +82,6 @@ func DownloadAudioFiles(progressChan chan<- DownloadStatus, filenames []string, Msg: "Starting download...", } - totalDownloaded := int64(0) - // Download each file that doesn't exist for _, filename := range filesToDownload { url := urlBase + filename diff --git a/internal/page/home.go b/internal/page/home.go index 8b128bc..131d1b3 100644 --- a/internal/page/home.go +++ b/internal/page/home.go @@ -153,47 +153,81 @@ func (p *Home) HandleEvent(event *sdl.Event) error { return nil } -// Update updates animations and changing textures and other changes using `dt` which represents a time delta in float32. func (p *Home) Update(dt float32) error { - select { - case progressUpdate, ok := <-p.Context.MessageChannel: - if !ok { - // Channel is closed, set message to READY - newMsg, err := NewStringItem("Status: READY", p.font, colors.Green) - if err != nil { - return err + var ( + progressUpdate download.DownloadStatus + ok bool + gotUpdate bool + ) + + // Drain the channel, keeping only the newest update. + for { + select { + case progressUpdate, ok = <-p.Context.MessageChannel: + gotUpdate = true + + if !ok { + // Channel was closed while draining. + newMsg, err := NewStringItem("Status: READY", p.font, colors.Green) + if err != nil { + return err + } + messageScale := float32(28) / float32(p.baseFontSize) + newMsg.W = int32(float32(newMsg.W) * messageScale) + newMsg.H = int32(float32(newMsg.H) * messageScale) + p.message = newMsg + p.isDownloadComplete = true + + return nil } - messageScale := float32(28) / float32(p.baseFontSize) - newMsg.W = int32(float32(newMsg.W) * messageScale) - newMsg.H = int32(float32(newMsg.H) * messageScale) - p.message = newMsg - p.isDownloadComplete = true - } else if progressUpdate.Err != nil { - // Handle error - newMsg, err := NewStringItem(fmt.Sprintf("Status: %s", progressUpdate.Err.Error), p.font, colors.Red) - if err != nil { - return err - } - messageScale := float32(28) / float32(p.baseFontSize) - newMsg.W = int32(float32(newMsg.W) * messageScale) - newMsg.H = int32(float32(newMsg.H) * messageScale) - p.message = newMsg - } else { - // Update progress message - percentComplete := float64(progressUpdate.Cur) / float64(progressUpdate.Max) * 100 - msg := fmt.Sprintf("Status: Downloading assets %.1f%% Complete", percentComplete) - newMsg, err := NewStringItem(msg, p.font, colors.White) - if err != nil { - return err - } - messageScale := float32(28) / float32(p.baseFontSize) - newMsg.W = int32(float32(newMsg.W) * messageScale) - newMsg.H = int32(float32(newMsg.H) * messageScale) - p.message = newMsg + + default: + goto drained } - default: - // No update, do nothing } + +drained: + + if !gotUpdate { + return nil + } + + if progressUpdate.Err != nil { + // Handle error + newMsg, err := NewStringItem( + fmt.Sprintf("Status: %s", progressUpdate.Err.Error()), + p.font, + colors.Red, + ) + if err != nil { + return err + } + + messageScale := float32(28) / float32(p.baseFontSize) + newMsg.W = int32(float32(newMsg.W) * messageScale) + newMsg.H = int32(float32(newMsg.H) * messageScale) + p.message = newMsg + + } else { + // Update progress message using ONLY the latest update. + percentComplete := float64(progressUpdate.Cur) / float64(progressUpdate.Max) * 100 + + msg := fmt.Sprintf( + "Status: Downloading assets %.1f%% Complete", + percentComplete, + ) + + newMsg, err := NewStringItem(msg, p.font, colors.White) + if err != nil { + return err + } + + messageScale := float32(28) / float32(p.baseFontSize) + newMsg.W = int32(float32(newMsg.W) * messageScale) + newMsg.H = int32(float32(newMsg.H) * messageScale) + p.message = newMsg + } + return nil }