Rename the Default theme option to System.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-04 21:49:06 +03:00
parent 648325a690
commit b2402f4c72
10 changed files with 57 additions and 23 deletions
+2 -2
View File
@@ -483,8 +483,8 @@ func validateConfig(config domain.Config) error {
}
// Empty Theme is accepted and normalized to the branded theme on load, so
// older configs (and hand-built ones) stay valid without an explicit theme.
if config.Theme != "" && config.Theme != domain.ThemeDefault && config.Theme != domain.ThemeGoSentry {
return errors.New("theme must be 'default' or 'gosentry'")
if config.Theme != "" && config.Theme != domain.ThemeSystem && config.Theme != domain.ThemeGoSentry {
return errors.New("theme must be 'system' or 'gosentry'")
}
return nil
}
+2 -2
View File
@@ -21,8 +21,8 @@ const (
type Theme string
const (
// ThemeDefault keeps Fyne's built-in theme — the original look.
ThemeDefault Theme = "default"
// ThemeSystem keeps Fyne's built-in theme, following the platform look.
ThemeSystem Theme = "system"
// ThemeGoSentry applies the branded teal/amber theme derived from the logo
// and app icon.
ThemeGoSentry Theme = "gosentry"
+3
View File
@@ -120,6 +120,9 @@ func loadOrCreateConfig(paths Paths) (domain.Config, error) {
if config.Theme == "" {
config.Theme = domain.ThemeGoSentry
}
if config.Theme == "default" {
config.Theme = domain.ThemeSystem
}
return config, nil
}
+28
View File
@@ -183,6 +183,34 @@ func TestLoadOrCreateConfigCreatesDefaultsOnFirstRun(t *testing.T) {
}
}
// TestLoadOrCreateConfigMigratesLegacyThemeDefault covers a gosentry.json that
// still stores the retired "default" theme value: load normalizes it to system.
func TestLoadOrCreateConfigMigratesLegacyThemeDefault(t *testing.T) {
dir := t.TempDir()
paths := Paths{
AppDir: dir,
ConfigPath: filepath.Join(dir, ConfigFileName),
}
legacy := map[string]any{
"jobs_file": "jobs.json",
"logs_dir": "logs",
"max_log_files": 100,
"max_log_age_days": 30,
"theme": "default",
}
if err := writeJSON(paths.ConfigPath, legacy); err != nil {
t.Fatal(err)
}
got, err := loadOrCreateConfig(paths)
if err != nil {
t.Fatal(err)
}
if got.Theme != domain.ThemeSystem {
t.Errorf("migrated Theme = %q, want %q", got.Theme, domain.ThemeSystem)
}
}
// TestLoadOrCreateConfigKeepsZeroTimeoutOnReload guards the "0 = no timeout"
// setting against being normalized away when an existing gosentry.json is read
// back. Loading must not treat 0 as a missing value.
+6 -6
View File
@@ -61,7 +61,7 @@ func settingsView(w fyne.Window, svc *app.Service) fyne.CanvasObject {
notifications := widget.NewCheck("Show desktop notifications for failed jobs", nil)
notifications.SetChecked(store.Config.NotifyOnFailure)
notifications.OnChanged = func(bool) { updateSaveState() }
themeSelect := widget.NewSelect([]string{themeLabelDefault, themeLabelGoSentry}, nil)
themeSelect := widget.NewSelect([]string{themeLabelSystem, themeLabelGoSentry}, nil)
themeSelect.SetSelected(themeLabel(store.Config.Theme))
// Preview the theme the moment it is picked so the choice is visible before
// saving; Save persists it. Reverting the selection reverts the preview, and
@@ -256,15 +256,15 @@ func settingsView(w fyne.Window, svc *app.Service) fyne.CanvasObject {
// Theme dropdown labels. These are the human-facing captions; themeLabel and
// themeFromLabel translate between them and the stored domain.Theme values so the
// select never leaks the on-disk "default"/"gosentry" strings to the user.
// select never leaks the on-disk "system"/"gosentry" strings to the user.
const (
themeLabelDefault = "Default"
themeLabelSystem = "System"
themeLabelGoSentry = "GoSentry"
)
func themeLabel(choice domain.Theme) string {
if choice == domain.ThemeDefault {
return themeLabelDefault
if choice == domain.ThemeSystem {
return themeLabelSystem
}
return themeLabelGoSentry
}
@@ -273,5 +273,5 @@ func themeFromLabel(label string) domain.Theme {
if label == themeLabelGoSentry {
return domain.ThemeGoSentry
}
return domain.ThemeDefault
return domain.ThemeSystem
}
+2 -2
View File
@@ -104,10 +104,10 @@ func (t gosentryTheme) Icon(name fyne.ThemeIconName) fyne.Resource { return t.ba
func (t gosentryTheme) Size(name fyne.ThemeSizeName) float32 { return t.base.Size(name) }
// themeFor maps a stored Theme choice to a concrete fyne.Theme. Only the
// explicit default choice keeps Fyne's built-in theme; everything else
// explicit system choice keeps Fyne's built-in theme; everything else
// (including the empty/legacy value) uses the branded GoSentry theme.
func themeFor(choice domain.Theme) fyne.Theme {
if choice == domain.ThemeDefault {
if choice == domain.ThemeSystem {
return theme.DefaultTheme()
}
return newGoSentryTheme()
+6 -6
View File
@@ -55,7 +55,7 @@ func TestGoSentryThemeDelegatesUnbrandedColors(t *testing.T) {
}
// themeFor maps the stored choice to the right theme: the GoSentry choice and the
// empty legacy value yield the branded teal primary; only the explicit default
// empty legacy value yield the branded teal primary; only the explicit system
// choice yields Fyne's built-in theme.
func TestThemeForChoice(t *testing.T) {
for _, choice := range []domain.Theme{domain.ThemeGoSentry, ""} {
@@ -64,9 +64,9 @@ func TestThemeForChoice(t *testing.T) {
t.Errorf("themeFor(%q) primary = %v, want brand teal %v", choice, got, brandTeal)
}
}
def := themeFor(domain.ThemeDefault)
if got := def.Color(theme.ColorNamePrimary, theme.VariantLight); got == brandTeal {
t.Errorf("themeFor(default) should not use the brand teal primary")
sys := themeFor(domain.ThemeSystem)
if got := sys.Color(theme.ColorNamePrimary, theme.VariantLight); got == brandTeal {
t.Errorf("themeFor(system) should not use the brand teal primary")
}
}
@@ -76,8 +76,8 @@ func TestThemeLabelRoundTrip(t *testing.T) {
if got := themeFromLabel(themeLabel(domain.ThemeGoSentry)); got != domain.ThemeGoSentry {
t.Errorf("round-trip gosentry = %q", got)
}
if got := themeFromLabel(themeLabel(domain.ThemeDefault)); got != domain.ThemeDefault {
t.Errorf("round-trip default = %q", got)
if got := themeFromLabel(themeLabel(domain.ThemeSystem)); got != domain.ThemeSystem {
t.Errorf("round-trip system = %q", got)
}
if got := themeLabel(""); got != themeLabelGoSentry {
t.Errorf("empty theme label = %q, want %q", got, themeLabelGoSentry)