fix: theme sometimes reverts on reopen — gate per-profile UI prefs on scope
The theme (and other per-profile UI prefs) are read via a.settings.Get, which is scoped to the active profile. GetUIPref only guarded on a.settings==nil, so in the startup window AFTER NewStore but BEFORE SetProfile(active) it resolved with the wrong (empty) scope. The frontend theme self-heal treats a resolved "" as "answered, unset → keep default, stop retrying", so a race landed on the light default and stayed. Add a settingsScoped atomic flag set right after SetProfile; GetUIPref/SetUIPref return "not ready" until then, so the frontend keeps retrying and restores the real theme. Also prevents seeding prefs into the wrong profile scope. Changelog entry added to 0.21.0 (EN+FR).
This commit is contained in:
@@ -515,6 +515,7 @@ type App struct {
|
||||
pttKeyedMethod string // "cat" | "rts" | "dtr" while keyed; "" when idle
|
||||
pttGen int64 // bumped on every key; a delayed unkey only fires if unchanged (guards against a stale release cutting a new transmission)
|
||||
startupErr string // captured for surfacing to the frontend
|
||||
settingsScoped atomic.Bool // true once a.settings is scoped to the active profile — GetUIPref/SetUIPref (per-profile) must wait for it, else an early call reads the wrong scope and e.g. resets the theme
|
||||
dbPath string // settings/config database file (settings + profiles); may be a user-chosen location
|
||||
logbookPath string // default SQLite logbook file (QSOs), next to the settings db — used when a profile doesn't point elsewhere
|
||||
logDb *sql.DB // QSO logbook connection — MySQL, a per-profile SQLite file, or the default logbook.db (never the settings db, except on fallback)
|
||||
@@ -848,6 +849,7 @@ func (a *App) startup(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
a.settings.SetProfile(active.ID)
|
||||
a.settingsScoped.Store(true) // per-profile settings reads (GetUIPref…) are now safe
|
||||
// US county resolver — its own local SQLite (data/uls.db), populated on demand
|
||||
// by DownloadULSCounties. Opening (creating an empty store) is cheap and never
|
||||
// fatal: county resolution simply stays inert until the operator downloads it.
|
||||
@@ -2013,10 +2015,12 @@ func (a *App) groupDigitalSlots() bool {
|
||||
}
|
||||
|
||||
func (a *App) GetUIPref(key string) (string, error) {
|
||||
if a.settings == nil {
|
||||
if a.settings == nil || !a.settingsScoped.Load() {
|
||||
// Distinct from a genuinely-empty pref: the (LOCAL SQLite) settings store
|
||||
// isn't wired yet. There's a brief window at launch where the frontend can
|
||||
// call this before OnStartup has opened the DB and built the store. The UI
|
||||
// isn't wired AND scoped to the active profile yet. There's a brief window at
|
||||
// launch where the frontend can call this before it's ready — reading then
|
||||
// returns the wrong profile's (empty) value, which stopped the theme
|
||||
// self-heal early ("dark theme reverts to light on reopen"). The UI
|
||||
// uses the error to keep RETRYING rather than treat it as "unset" and fall
|
||||
// back to a default — the "dark theme reverts to light after an update" bug
|
||||
// (the update cleared localStorage, and the DB read gave up too early while
|
||||
@@ -2027,8 +2031,8 @@ func (a *App) GetUIPref(key string) (string, error) {
|
||||
}
|
||||
|
||||
func (a *App) SetUIPref(key, value string) error {
|
||||
if a.settings == nil {
|
||||
return fmt.Errorf("db not initialized")
|
||||
if a.settings == nil || !a.settingsScoped.Load() {
|
||||
return fmt.Errorf("settings store not ready") // avoid seeding the wrong profile scope
|
||||
}
|
||||
return a.settings.Set(a.ctx, "ui."+key, value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user