Skip to content

Commit ad7ab5d

Browse files
committed
Overhaul progress bar system
- Introduced progress callbacks for font installation and removal processes, allowing for more granular updates in the UI. - Updated relevant functions to accept progress functions, improving user feedback during operations. - Refactored archive extraction to support progress notifications for extracted font files. - Improved overall code structure for better readability and maintainability.
1 parent c41de38 commit ad7ab5d

11 files changed

Lines changed: 662 additions & 53 deletions

File tree

cmd/add.go

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,31 @@ Use --scope to set installation location:
704704
send(components.ProgressUpdateMsg{Percent: percent})
705705

706706
// Install the font using the installFont helper
707+
lastStep := ""
708+
lastPctBucket := -1
709+
onProgress := func(step string, stepPct float64) {
710+
// Avoid spamming the UI: only update on step change or ~5% within-step progress.
711+
bucket := int(shared.Clamp01(stepPct) * 20.0) // 0..20
712+
if step == lastStep && bucket == lastPctBucket {
713+
return
714+
}
715+
lastStep = step
716+
lastPctBucket = bucket
717+
718+
msg := step + "..."
719+
if step == installStepDownload {
720+
msg = "Downloading from " + fontGroup.SourceName
721+
}
722+
723+
send(components.ItemUpdateMsg{
724+
Index: itemIndex,
725+
Status: "in_progress",
726+
Message: msg,
727+
})
728+
send(components.ProgressUpdateMsg{
729+
Percent: OverallInstallPercent(itemIndex, len(fontsToInstall), step, stepPct),
730+
})
731+
}
707732
result, err := installFont(
708733
fontGroup.Fonts,
709734
fontGroup.FontID,
@@ -712,6 +737,7 @@ Use --scope to set installation location:
712737
force,
713738
fontDir,
714739
true, // suppress per-file verbose download lines while Bubble Tea owns stdout
740+
onProgress,
715741
)
716742

717743
if err != nil {
@@ -800,8 +826,7 @@ Use --scope to set installation location:
800826
})
801827

802828
// Update progress percentage - now based on actual completion
803-
percent = float64(itemIndex+1) / float64(len(fontsToInstall)) * 100
804-
send(components.ProgressUpdateMsg{Percent: percent})
829+
send(components.ProgressUpdateMsg{Percent: OverallInstallPercent(itemIndex, len(fontsToInstall), installStepCompleted, 1)})
805830
}
806831

807832
return nil
@@ -942,6 +967,7 @@ func installFontsInDebugMode(fontManager platform.FontManager, fontsToInstall []
942967
force,
943968
fontDir,
944969
false, // debug path: allow per-file verbose download lines
970+
nil,
945971
)
946972

947973
if err != nil {
@@ -1034,13 +1060,37 @@ func humanizeFontStyleLabel(s string) string {
10341060
}
10351061

10361062
// downloadFontVariants downloads all variants of a font family
1037-
func downloadFontVariants(fontFiles []repo.FontFile, tempDir string, downloadOpts *repo.DownloadFontOptions) ([]string, error) {
1063+
func downloadFontVariants(fontFiles []repo.FontFile, tempDir string, downloadOpts *repo.DownloadFontOptions, onProgress StepProgressFunc) ([]string, error) {
10381064
var allFontPaths []string
10391065

10401066
// Download each variant - only log errors and unusual cases
1041-
for _, fontFile := range fontFiles {
1067+
total := len(fontFiles)
1068+
for i, fontFile := range fontFiles {
1069+
if onProgress != nil && total > 0 {
1070+
onProgress(installStepDownload, float64(i)/float64(total))
1071+
}
1072+
opts := downloadOpts
1073+
if onProgress != nil {
1074+
// Ensure we always pass a progress-enabled options struct, while preserving suppression.
1075+
suppress := opts != nil && opts.SuppressVerboseProgressLine
1076+
opts = &repo.DownloadFontOptions{SuppressVerboseProgressLine: suppress}
1077+
opts.OnBytesDownloaded = func(doneBytes int64, totalBytes int64) {
1078+
if totalBytes > 0 {
1079+
onProgress(installStepDownload, float64(doneBytes)/float64(totalBytes))
1080+
}
1081+
}
1082+
opts.OnExtractProgress = func(done int, total int) {
1083+
if total > 0 {
1084+
onProgress(installStepExtract, float64(done)/float64(total))
1085+
return
1086+
}
1087+
// Unknown totals (e.g., tar streams): use a soft-saturating curve so the UI moves.
1088+
onProgress(installStepExtract, float64(done)/float64(done+12))
1089+
}
1090+
}
1091+
10421092
output.GetDebug().State("Calling repo.DownloadAndExtractFont() for variant: %s from %s", fontFile.Variant, fontFile.DownloadURL)
1043-
fontPaths, err := repo.DownloadAndExtractFont(&fontFile, tempDir, downloadOpts)
1093+
fontPaths, err := repo.DownloadAndExtractFont(&fontFile, tempDir, opts)
10441094
if err != nil {
10451095
output.GetDebug().State("repo.DownloadAndExtractFont() failed for variant %s: %v", fontFile.Variant, err)
10461096
return nil, err
@@ -1052,18 +1102,26 @@ func downloadFontVariants(fontFiles []repo.FontFile, tempDir string, downloadOpt
10521102
}
10531103
}
10541104

1105+
if onProgress != nil {
1106+
onProgress(installStepDownload, 1)
1107+
onProgress(installStepExtract, 1)
1108+
}
10551109
return allFontPaths, nil
10561110
}
10571111

10581112
// installDownloadedFonts installs downloaded font files to system
1059-
func installDownloadedFonts(fontPaths []string, fontManager platform.FontManager, installScope platform.InstallationScope, fontDir string, force bool) (installed, skipped, failed int, details []string, errors []string, downloadSize int64) {
1113+
func installDownloadedFonts(fontPaths []string, fontManager platform.FontManager, installScope platform.InstallationScope, fontDir string, force bool, onProgress StepProgressFunc) (installed, skipped, failed int, details []string, errors []string, downloadSize int64) {
10601114
var installedFiles []string
10611115
var skippedFiles []string
10621116
var failedFiles []string
10631117

10641118
batchOpts := &platform.InstallFontOptions{SkipPostInstallCacheRefresh: true}
10651119

1066-
for _, fontPath := range fontPaths {
1120+
total := len(fontPaths)
1121+
for i, fontPath := range fontPaths {
1122+
if onProgress != nil && total > 0 {
1123+
onProgress(installStepInstall, float64(i)/float64(total))
1124+
}
10671125
fontDisplayName := filepath.Base(fontPath)
10681126

10691127
// Get file size before we potentially remove it
@@ -1106,8 +1164,15 @@ func installDownloadedFonts(fontPaths []string, fontManager platform.FontManager
11061164
installedFiles = append(installedFiles, fontDisplayName)
11071165
}
11081166

1167+
if onProgress != nil {
1168+
onProgress(installStepInstall, 1)
1169+
}
1170+
11091171
// Single cache refresh / font-change notification after all copies (avoids pkill fontd / fc-cache / WM_FONTCHANGE per file)
11101172
if installed > 0 {
1173+
if onProgress != nil {
1174+
onProgress(installStepFinalize, 0)
1175+
}
11111176
if flushErr := fontManager.FlushFontCache(installScope); flushErr != nil {
11121177
errStr := flushErr.Error()
11131178
isDarwinNonCritical := strings.Contains(strings.ToLower(errStr), "failed to refresh font cache (non-critical")
@@ -1119,6 +1184,9 @@ func installDownloadedFonts(fontPaths []string, fontManager platform.FontManager
11191184
output.GetDebug().Error("Post-install font cache flush failed: %v", flushErr)
11201185
}
11211186
}
1187+
if onProgress != nil {
1188+
onProgress(installStepFinalize, 1)
1189+
}
11221190
}
11231191

11241192
// Store categorized details: installed, then skipped, then failed
@@ -1168,7 +1236,11 @@ func installFont(
11681236
force bool,
11691237
fontDir string,
11701238
suppressVerboseDownloads bool,
1239+
onProgress StepProgressFunc,
11711240
) (*InstallResult, error) {
1241+
if onProgress != nil {
1242+
onProgress(installStepPrecheck, 0)
1243+
}
11721244
// Check if font is already installed BEFORE downloading (unless force flag is set)
11731245
// This saves bandwidth by skipping downloads for already-installed fonts
11741246
if !force && fontID != "" && len(fontFiles) > 0 {
@@ -1182,6 +1254,10 @@ func installFont(
11821254
// Log warning but continue with installation (fail-safe behavior)
11831255
GetLogger().Warn("Failed to check if font is already installed (ID: %s): %v. Proceeding with installation.", fontID, checkErr)
11841256
} else if alreadyInstalled {
1257+
if onProgress != nil {
1258+
onProgress(installStepPrecheck, 1)
1259+
onProgress(installStepCompleted, 1)
1260+
}
11851261
// Font is already installed - skip download and mark all variants as skipped
11861262
output.GetDebug().State("Font %s (ID: %s) is already installed, skipping download", fontName, fontID)
11871263
var details []string
@@ -1191,6 +1267,9 @@ func installFont(
11911267
return buildInstallResult(InstallStatusSkipped, "Already installed", 0, len(fontFiles), 0, details, nil, 0), nil
11921268
}
11931269
}
1270+
if onProgress != nil {
1271+
onProgress(installStepPrecheck, 1)
1272+
}
11941273

11951274
// Download all variants of this font family
11961275
tempDir, err := platform.GetTempFontsDir()
@@ -1211,14 +1290,17 @@ func installFont(
12111290
if suppressVerboseDownloads {
12121291
downloadOpts = &repo.DownloadFontOptions{SuppressVerboseProgressLine: true}
12131292
}
1214-
allFontPaths, downloadErr := downloadFontVariants(fontFiles, tempDir, downloadOpts)
1293+
if onProgress != nil {
1294+
onProgress(installStepDownload, 0)
1295+
}
1296+
allFontPaths, downloadErr := downloadFontVariants(fontFiles, tempDir, downloadOpts, onProgress)
12151297
if downloadErr != nil {
12161298
return buildInstallResult(InstallStatusFailed, "Download failed", 0, 0, len(fontFiles), nil, nil, 0), downloadErr
12171299
}
12181300

12191301
// Install downloaded fonts
12201302
installed, skipped, failed, details, errors, downloadSize := installDownloadedFonts(
1221-
allFontPaths, fontManager, installScope, fontDir, force)
1303+
allFontPaths, fontManager, installScope, fontDir, force, onProgress)
12221304

12231305
// Determine final status
12241306
status := InstallStatusCompleted

0 commit comments

Comments
 (0)