fix(ui): send complete engine settings update
- commit
- 84747b2960fa71b189f34de0f4981ddcbc8988b4
- author
- brice · · 2026-06-23 13:45 UTC
- committer
- brice · · 2026-06-23 20:01 UTC
- parent
- 5294200
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +63 -6
M cmd/dumber/main.go +5 -2
| @@ -867,8 +867,11 @@ func buildUIDependencies( | |||
| 867 | 867 | browserLauncher := desktop.NewBrowserLauncher(browserLaunchRelay) | |
| 868 | 868 | ||
| 869 | 869 | uiDeps := &ui.Dependencies{ | |
| 870 | - | Ctx: ctx, | |
| 871 | - | Config: cfg, | |
| 870 | + | Ctx: ctx, | |
| 871 | + | Config: cfg, | |
| 872 | + | EngineSettingsPayload: func() port.EngineSettingsPayload { | |
| 873 | + | return bootstrap.EngineSettingsPayloadFromConfig(cfg) | |
| 874 | + | }, | |
| 872 | 875 | InitialURL: initialURL, | |
| 873 | 876 | RestoreSessionID: restoreSessionID, | |
| 874 | 877 | StartupCrashReports: startupCrashReports, | |
| @@ -867,8 +867,11 @@ func buildUIDependencies( | |||||
| 867 | browserLauncher := desktop.NewBrowserLauncher(browserLaunchRelay) | 867 | browserLauncher := desktop.NewBrowserLauncher(browserLaunchRelay) | ||
| 868 | 868 | ||||
| 869 | uiDeps := &ui.Dependencies{ | 869 | uiDeps := &ui.Dependencies{ | ||
| 870 | - | Ctx: ctx, | 870 | + | Ctx: ctx, |
| 871 | - | Config: cfg, | 871 | + | Config: cfg, |
| 872 | + | EngineSettingsPayload: func() port.EngineSettingsPayload { | |||
| 873 | + | return bootstrap.EngineSettingsPayloadFromConfig(cfg) | |||
| 874 | + | }, | |||
| 872 | InitialURL: initialURL, | 875 | InitialURL: initialURL, | ||
| 873 | RestoreSessionID: restoreSessionID, | 876 | RestoreSessionID: restoreSessionID, | ||
| 874 | StartupCrashReports: startupCrashReports, | 877 | StartupCrashReports: startupCrashReports, | ||
M internal/ui/app.go +5 -2
| @@ -5118,9 +5118,12 @@ func (a *App) applyAppearanceConfig(ctx context.Context) { | |||
| 5118 | 5118 | cfg := a.deps.Config | |
| 5119 | 5119 | ||
| 5120 | 5120 | if a.engine != nil { | |
| 5121 | + | settings := port.EngineSettingsPayload{DefaultUIScale: cfg.DefaultUIScale} | |
| 5122 | + | if a.deps.EngineSettingsPayload != nil { | |
| 5123 | + | settings = a.deps.EngineSettingsPayload() | |
| 5124 | + | } | |
| 5121 | 5125 | if err := a.engine.UpdateSettings(ctx, port.EngineSettingsUpdate{ | |
| 5122 | - | Settings: port.EngineSettingsPayload{DefaultUIScale: cfg.DefaultUIScale}, | |
| 5123 | - | Raw: cfg, | |
| 5126 | + | Settings: settings, | |
| 5124 | 5127 | }); err != nil { | |
| 5125 | 5128 | log.Warn().Err(err).Msg("failed to apply engine settings update") | |
| 5126 | 5129 | } | |
| @@ -5118,9 +5118,12 @@ func (a *App) applyAppearanceConfig(ctx context.Context) { | |||||
| 5118 | cfg := a.deps.Config | 5118 | cfg := a.deps.Config | ||
| 5119 | 5119 | ||||
| 5120 | if a.engine != nil { | 5120 | if a.engine != nil { | ||
| 5121 | + | settings := port.EngineSettingsPayload{DefaultUIScale: cfg.DefaultUIScale} | |||
| 5122 | + | if a.deps.EngineSettingsPayload != nil { | |||
| 5123 | + | settings = a.deps.EngineSettingsPayload() | |||
| 5124 | + | } | |||
| 5121 | if err := a.engine.UpdateSettings(ctx, port.EngineSettingsUpdate{ | 5125 | if err := a.engine.UpdateSettings(ctx, port.EngineSettingsUpdate{ | ||
| 5122 | - | Settings: port.EngineSettingsPayload{DefaultUIScale: cfg.DefaultUIScale}, | 5126 | + | Settings: settings, |
| 5123 | - | Raw: cfg, | |||
| 5124 | }); err != nil { | 5127 | }); err != nil { | ||
| 5125 | log.Warn().Err(err).Msg("failed to apply engine settings update") | 5128 | log.Warn().Err(err).Msg("failed to apply engine settings update") | ||
| 5126 | } | 5129 | } | ||
M internal/ui/deps.go +3 -2
| @@ -20,8 +20,9 @@ type Dependencies struct { | |||
| 20 | 20 | // Core context and configuration | |
| 21 | 21 | Ctx context.Context | |
| 22 | 22 | Config *config.Config // TODO: replace with port interface in a later milestone | |
| 23 | - | InitialURL string // URL to open on startup (optional) | |
| 24 | - | RestoreSessionID string // Session ID to restore on startup (optional) | |
| 23 | + | EngineSettingsPayload func() port.EngineSettingsPayload | |
| 24 | + | InitialURL string // URL to open on startup (optional) | |
| 25 | + | RestoreSessionID string // Session ID to restore on startup (optional) | |
| 25 | 26 | StartupCrashReports []string | |
| 26 | 27 | OnFirstWebViewShown func(context.Context) | |
| 27 | 28 | OnSessionPersisted func() // Called by main after session is persisted to DB | |
| @@ -20,8 +20,9 @@ type Dependencies struct { | |||||
| 20 | // Core context and configuration | 20 | // Core context and configuration | ||
| 21 | Ctx context.Context | 21 | Ctx context.Context | ||
| 22 | Config *config.Config // TODO: replace with port interface in a later milestone | 22 | Config *config.Config // TODO: replace with port interface in a later milestone | ||
| 23 | - | InitialURL string // URL to open on startup (optional) | 23 | + | EngineSettingsPayload func() port.EngineSettingsPayload |
| 24 | - | RestoreSessionID string // Session ID to restore on startup (optional) | 24 | + | InitialURL string // URL to open on startup (optional) |
| 25 | + | RestoreSessionID string // Session ID to restore on startup (optional) | |||
| 25 | StartupCrashReports []string | 26 | StartupCrashReports []string | ||
| 26 | OnFirstWebViewShown func(context.Context) | 27 | OnFirstWebViewShown func(context.Context) | ||
| 27 | OnSessionPersisted func() // Called by main after session is persisted to DB | 28 | OnSessionPersisted func() // Called by main after session is persisted to DB | ||
M internal/ui/external_theme_reload_test.go +50 -0
| @@ -8,6 +8,7 @@ import ( | |||
| 8 | 8 | "github.com/stretchr/testify/mock" | |
| 9 | 9 | "github.com/stretchr/testify/require" | |
| 10 | 10 | ||
| 11 | + | "github.com/bnema/dumber/internal/application/port" | |
| 11 | 12 | portmocks "github.com/bnema/dumber/internal/application/port/mocks" | |
| 12 | 13 | "github.com/bnema/dumber/internal/application/usecase" | |
| 13 | 14 | "github.com/bnema/dumber/internal/domain/entity" | |
| @@ -68,6 +69,55 @@ func immediateDispatchForExternalThemeTest(label string, fn func()) syncdispatch | |||
| 68 | 69 | return syncdispatch.SyncDispatchResult{Label: label, Status: syncdispatch.SyncDispatchCompleted} | |
| 69 | 70 | } | |
| 70 | 71 | ||
| 72 | + | func TestApplyAppearanceConfigSendsCompleteEngineSettingsPayload(t *testing.T) { | |
| 73 | + | ctx := context.Background() | |
| 74 | + | cfg := config.DefaultConfig() | |
| 75 | + | cfg.DefaultUIScale = 1.25 | |
| 76 | + | cfg.Appearance.SansFont = "Inter" | |
| 77 | + | cfg.Appearance.SerifFont = "Literata" | |
| 78 | + | cfg.Appearance.MonospaceFont = "Fira Code" | |
| 79 | + | cfg.Appearance.DefaultFontSize = 17 | |
| 80 | + | cfg.Debug.EnableDevTools = true | |
| 81 | + | cfg.Logging.CaptureConsole = true | |
| 82 | + | cfg.Engine.WebKit.DrawCompositingIndicators = true | |
| 83 | + | cfg.Media.HardwareDecodingMode = config.HardwareDecodingForce | |
| 84 | + | expected := port.EngineSettingsPayload{ | |
| 85 | + | DefaultUIScale: cfg.DefaultUIScale, | |
| 86 | + | WebContent: port.EngineWebContentSettingsPayload{ | |
| 87 | + | SansFont: cfg.Appearance.SansFont, | |
| 88 | + | SerifFont: cfg.Appearance.SerifFont, | |
| 89 | + | MonospaceFont: cfg.Appearance.MonospaceFont, | |
| 90 | + | DefaultFontSize: cfg.Appearance.DefaultFontSize, | |
| 91 | + | EnableDevTools: cfg.Debug.EnableDevTools, | |
| 92 | + | CaptureConsole: cfg.Logging.CaptureConsole, | |
| 93 | + | DrawCompositingIndicators: cfg.Engine.WebKit.DrawCompositingIndicators, | |
| 94 | + | HardwareDecoding: port.EngineHardwareDecodingForce, | |
| 95 | + | }, | |
| 96 | + | } | |
| 97 | + | engine := portmocks.NewMockEngine(t) | |
| 98 | + | var captured port.EngineSettingsUpdate | |
| 99 | + | engine.EXPECT().UpdateSettings(mock.Anything, mock.Anything). | |
| 100 | + | Run(func(_ context.Context, update port.EngineSettingsUpdate) { | |
| 101 | + | captured = update | |
| 102 | + | }). | |
| 103 | + | Return(nil). | |
| 104 | + | Once() | |
| 105 | + | app := &App{ | |
| 106 | + | deps: &Dependencies{ | |
| 107 | + | Config: cfg, | |
| 108 | + | EngineSettingsPayload: func() port.EngineSettingsPayload { | |
| 109 | + | return expected | |
| 110 | + | }, | |
| 111 | + | }, | |
| 112 | + | engine: engine, | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | app.applyAppearanceConfig(ctx) | |
| 116 | + | ||
| 117 | + | require.Equal(t, expected, captured.Settings) | |
| 118 | + | require.Nil(t, captured.Raw) | |
| 119 | + | } | |
| 120 | + | ||
| 71 | 121 | func TestExternalThemeWatcherCallbackAppliesThemeThroughSharedPath(t *testing.T) { | |
| 72 | 122 | ctx := context.Background() | |
| 73 | 123 | cfg := config.DefaultConfig() | |
| @@ -8,6 +8,7 @@ import ( | |||||
| 8 | "github.com/stretchr/testify/mock" | 8 | "github.com/stretchr/testify/mock" | ||
| 9 | "github.com/stretchr/testify/require" | 9 | "github.com/stretchr/testify/require" | ||
| 10 | 10 | ||||
| 11 | + | "github.com/bnema/dumber/internal/application/port" | |||
| 11 | portmocks "github.com/bnema/dumber/internal/application/port/mocks" | 12 | portmocks "github.com/bnema/dumber/internal/application/port/mocks" | ||
| 12 | "github.com/bnema/dumber/internal/application/usecase" | 13 | "github.com/bnema/dumber/internal/application/usecase" | ||
| 13 | "github.com/bnema/dumber/internal/domain/entity" | 14 | "github.com/bnema/dumber/internal/domain/entity" | ||
| @@ -68,6 +69,55 @@ func immediateDispatchForExternalThemeTest(label string, fn func()) syncdispatch | |||||
| 68 | return syncdispatch.SyncDispatchResult{Label: label, Status: syncdispatch.SyncDispatchCompleted} | 69 | return syncdispatch.SyncDispatchResult{Label: label, Status: syncdispatch.SyncDispatchCompleted} | ||
| 69 | } | 70 | } | ||
| 70 | 71 | ||||
| 72 | + | func TestApplyAppearanceConfigSendsCompleteEngineSettingsPayload(t *testing.T) { | |||
| 73 | + | ctx := context.Background() | |||
| 74 | + | cfg := config.DefaultConfig() | |||
| 75 | + | cfg.DefaultUIScale = 1.25 | |||
| 76 | + | cfg.Appearance.SansFont = "Inter" | |||
| 77 | + | cfg.Appearance.SerifFont = "Literata" | |||
| 78 | + | cfg.Appearance.MonospaceFont = "Fira Code" | |||
| 79 | + | cfg.Appearance.DefaultFontSize = 17 | |||
| 80 | + | cfg.Debug.EnableDevTools = true | |||
| 81 | + | cfg.Logging.CaptureConsole = true | |||
| 82 | + | cfg.Engine.WebKit.DrawCompositingIndicators = true | |||
| 83 | + | cfg.Media.HardwareDecodingMode = config.HardwareDecodingForce | |||
| 84 | + | expected := port.EngineSettingsPayload{ | |||
| 85 | + | DefaultUIScale: cfg.DefaultUIScale, | |||
| 86 | + | WebContent: port.EngineWebContentSettingsPayload{ | |||
| 87 | + | SansFont: cfg.Appearance.SansFont, | |||
| 88 | + | SerifFont: cfg.Appearance.SerifFont, | |||
| 89 | + | MonospaceFont: cfg.Appearance.MonospaceFont, | |||
| 90 | + | DefaultFontSize: cfg.Appearance.DefaultFontSize, | |||
| 91 | + | EnableDevTools: cfg.Debug.EnableDevTools, | |||
| 92 | + | CaptureConsole: cfg.Logging.CaptureConsole, | |||
| 93 | + | DrawCompositingIndicators: cfg.Engine.WebKit.DrawCompositingIndicators, | |||
| 94 | + | HardwareDecoding: port.EngineHardwareDecodingForce, | |||
| 95 | + | }, | |||
| 96 | + | } | |||
| 97 | + | engine := portmocks.NewMockEngine(t) | |||
| 98 | + | var captured port.EngineSettingsUpdate | |||
| 99 | + | engine.EXPECT().UpdateSettings(mock.Anything, mock.Anything). | |||
| 100 | + | Run(func(_ context.Context, update port.EngineSettingsUpdate) { | |||
| 101 | + | captured = update | |||
| 102 | + | }). | |||
| 103 | + | Return(nil). | |||
| 104 | + | Once() | |||
| 105 | + | app := &App{ | |||
| 106 | + | deps: &Dependencies{ | |||
| 107 | + | Config: cfg, | |||
| 108 | + | EngineSettingsPayload: func() port.EngineSettingsPayload { | |||
| 109 | + | return expected | |||
| 110 | + | }, | |||
| 111 | + | }, | |||
| 112 | + | engine: engine, | |||
| 113 | + | } | |||
| 114 | + | ||||
| 115 | + | app.applyAppearanceConfig(ctx) | |||
| 116 | + | ||||
| 117 | + | require.Equal(t, expected, captured.Settings) | |||
| 118 | + | require.Nil(t, captured.Raw) | |||
| 119 | + | } | |||
| 120 | + | ||||
| 71 | func TestExternalThemeWatcherCallbackAppliesThemeThroughSharedPath(t *testing.T) { | 121 | func TestExternalThemeWatcherCallbackAppliesThemeThroughSharedPath(t *testing.T) { | ||
| 72 | ctx := context.Background() | 122 | ctx := context.Background() | ||
| 73 | cfg := config.DefaultConfig() | 123 | cfg := config.DefaultConfig() | ||