detached 13cc5a8

fix: address runtime config review findings

commit
13cc5a8d5559895d4acdcd2147c240f8551e2c4a
author
brice · · 2026-06-24 04:11 UTC
parent
42e6c82
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
23 files · +287 -238
M internal/application/port/engine.go +3 -36
@@ -6,6 +6,8 @@ package port
66 import (
77 "context"
88 "encoding/json"
9+
10+ "github.com/bnema/dumber/internal/domain/entity"
911 )
1012
1113 // CookiePolicy controls cookie acceptance behavior for the engine's network session.
@@ -136,47 +138,12 @@ type Engine interface {
136138 UpdateAppearance(ctx context.Context, r, g, b, alpha float64) error
137139
138140 // UpdateSettings applies runtime config changes to engine internals.
139- UpdateSettings(ctx context.Context, update EngineSettingsUpdate) error
141+ UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error
140142
141143 // SetHandlerContext sets the base context for message handler dispatch.
142144 SetHandlerContext(ctx context.Context)
143145 }
144146
145-// EngineHardwareDecodingMode controls engine-facing video hardware acceleration.
146-type EngineHardwareDecodingMode string
147-
148-const (
149- EngineHardwareDecodingAuto EngineHardwareDecodingMode = "auto"
150- EngineHardwareDecodingForce EngineHardwareDecodingMode = "force"
151- EngineHardwareDecodingDisable EngineHardwareDecodingMode = "disable"
152-)
153-
154-// EngineWebContentSettingsPayload is the engine-facing runtime view of web
155-// content settings that can be applied to newly-created or existing webviews.
156-type EngineWebContentSettingsPayload struct {
157- SansFont string
158- SerifFont string
159- MonospaceFont string
160- DefaultFontSize int
161- EnableDevTools bool
162- CaptureConsole bool
163- DrawCompositingIndicators bool
164- HardwareDecoding EngineHardwareDecodingMode
165- AutoCopyOnSelection bool
166-}
167-
168-// EngineSettingsPayload is the engine-facing boundary view of runtime config.
169-// Add fields here only when an engine needs to react to them at runtime.
170-type EngineSettingsPayload struct {
171- DefaultUIScale float64
172- WebContent EngineWebContentSettingsPayload
173-}
174-
175-// EngineSettingsUpdate carries a runtime config change to the engine.
176-type EngineSettingsUpdate struct {
177- Settings EngineSettingsPayload
178-}
179-
180147 // WebUIMessageHandler handles a decoded message payload from the JS bridge.
181148 // Used by both WebKit and CEF message routers via the shared handlers package.
182149 type WebUIMessageHandler interface {
@@ -6,6 +6,8 @@ package port
6 import (6 import (
7 "context"7 "context"
8 "encoding/json"8 "encoding/json"
9+
10+ "github.com/bnema/dumber/internal/domain/entity"
9 )11 )
10 12
11 // CookiePolicy controls cookie acceptance behavior for the engine's network session.13 // CookiePolicy controls cookie acceptance behavior for the engine's network session.
@@ -136,47 +138,12 @@ type Engine interface {
136 UpdateAppearance(ctx context.Context, r, g, b, alpha float64) error138 UpdateAppearance(ctx context.Context, r, g, b, alpha float64) error
137 139
138 // UpdateSettings applies runtime config changes to engine internals.140 // UpdateSettings applies runtime config changes to engine internals.
139- UpdateSettings(ctx context.Context, update EngineSettingsUpdate) error141+ UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error
140 142
141 // SetHandlerContext sets the base context for message handler dispatch.143 // SetHandlerContext sets the base context for message handler dispatch.
142 SetHandlerContext(ctx context.Context)144 SetHandlerContext(ctx context.Context)
143 }145 }
144 146
145-// EngineHardwareDecodingMode controls engine-facing video hardware acceleration.
146-type EngineHardwareDecodingMode string
147-
148-const (
149- EngineHardwareDecodingAuto EngineHardwareDecodingMode = "auto"
150- EngineHardwareDecodingForce EngineHardwareDecodingMode = "force"
151- EngineHardwareDecodingDisable EngineHardwareDecodingMode = "disable"
152-)
153-
154-// EngineWebContentSettingsPayload is the engine-facing runtime view of web
155-// content settings that can be applied to newly-created or existing webviews.
156-type EngineWebContentSettingsPayload struct {
157- SansFont string
158- SerifFont string
159- MonospaceFont string
160- DefaultFontSize int
161- EnableDevTools bool
162- CaptureConsole bool
163- DrawCompositingIndicators bool
164- HardwareDecoding EngineHardwareDecodingMode
165- AutoCopyOnSelection bool
166-}
167-
168-// EngineSettingsPayload is the engine-facing boundary view of runtime config.
169-// Add fields here only when an engine needs to react to them at runtime.
170-type EngineSettingsPayload struct {
171- DefaultUIScale float64
172- WebContent EngineWebContentSettingsPayload
173-}
174-
175-// EngineSettingsUpdate carries a runtime config change to the engine.
176-type EngineSettingsUpdate struct {
177- Settings EngineSettingsPayload
178-}
179-
180 // WebUIMessageHandler handles a decoded message payload from the JS bridge.147 // WebUIMessageHandler handles a decoded message payload from the JS bridge.
181 // Used by both WebKit and CEF message routers via the shared handlers package.148 // Used by both WebKit and CEF message routers via the shared handlers package.
182 type WebUIMessageHandler interface {149 type WebUIMessageHandler interface {
M internal/application/port/mocks/engine.go +8 -7
@@ -9,6 +9,7 @@ import (
99 "encoding/json"
1010
1111 "github.com/bnema/dumber/internal/application/port"
12+ "github.com/bnema/dumber/internal/domain/entity"
1213 mock "github.com/stretchr/testify/mock"
1314 )
1415
@@ -905,7 +906,7 @@ func (_c *MockEngine_UpdateAppearance_Call) RunAndReturn(run func(ctx context.Co
905906 }
906907
907908 // UpdateSettings provides a mock function for the type MockEngine
908-func (_mock *MockEngine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {
909+func (_mock *MockEngine) UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error {
909910 ret := _mock.Called(ctx, update)
910911
911912 if len(ret) == 0 {
@@ -913,7 +914,7 @@ func (_mock *MockEngine) UpdateSettings(ctx context.Context, update port.EngineS
913914 }
914915
915916 var r0 error
916- if returnFunc, ok := ret.Get(0).(func(context.Context, port.EngineSettingsUpdate) error); ok {
917+ if returnFunc, ok := ret.Get(0).(func(context.Context, entity.EngineSettingsUpdate) error); ok {
917918 r0 = returnFunc(ctx, update)
918919 } else {
919920 r0 = ret.Error(0)
@@ -928,20 +929,20 @@ type MockEngine_UpdateSettings_Call struct {
928929
929930 // UpdateSettings is a helper method to define mock.On call
930931 // - ctx context.Context
931-// - update port.EngineSettingsUpdate
932+// - update entity.EngineSettingsUpdate
932933 func (_e *MockEngine_Expecter) UpdateSettings(ctx any, update any) *MockEngine_UpdateSettings_Call {
933934 return &MockEngine_UpdateSettings_Call{Call: _e.mock.On("UpdateSettings", ctx, update)}
934935 }
935936
936-func (_c *MockEngine_UpdateSettings_Call) Run(run func(ctx context.Context, update port.EngineSettingsUpdate)) *MockEngine_UpdateSettings_Call {
937+func (_c *MockEngine_UpdateSettings_Call) Run(run func(ctx context.Context, update entity.EngineSettingsUpdate)) *MockEngine_UpdateSettings_Call {
937938 _c.Call.Run(func(args mock.Arguments) {
938939 var arg0 context.Context
939940 if args[0] != nil {
940941 arg0 = args[0].(context.Context)
941942 }
942- var arg1 port.EngineSettingsUpdate
943+ var arg1 entity.EngineSettingsUpdate
943944 if args[1] != nil {
944- arg1 = args[1].(port.EngineSettingsUpdate)
945+ arg1 = args[1].(entity.EngineSettingsUpdate)
945946 }
946947 run(
947948 arg0,
@@ -956,7 +957,7 @@ func (_c *MockEngine_UpdateSettings_Call) Return(err error) *MockEngine_UpdateSe
956957 return _c
957958 }
958959
959-func (_c *MockEngine_UpdateSettings_Call) RunAndReturn(run func(ctx context.Context, update port.EngineSettingsUpdate) error) *MockEngine_UpdateSettings_Call {
960+func (_c *MockEngine_UpdateSettings_Call) RunAndReturn(run func(ctx context.Context, update entity.EngineSettingsUpdate) error) *MockEngine_UpdateSettings_Call {
960961 _c.Call.Return(run)
961962 return _c
962963 }
@@ -9,6 +9,7 @@ import (
9 "encoding/json"9 "encoding/json"
10 10
11 "github.com/bnema/dumber/internal/application/port"11 "github.com/bnema/dumber/internal/application/port"
12+ "github.com/bnema/dumber/internal/domain/entity"
12 mock "github.com/stretchr/testify/mock"13 mock "github.com/stretchr/testify/mock"
13 )14 )
14 15
@@ -905,7 +906,7 @@ func (_c *MockEngine_UpdateAppearance_Call) RunAndReturn(run func(ctx context.Co
905 }906 }
906 907
907 // UpdateSettings provides a mock function for the type MockEngine908 // UpdateSettings provides a mock function for the type MockEngine
908-func (_mock *MockEngine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {909+func (_mock *MockEngine) UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error {
909 ret := _mock.Called(ctx, update)910 ret := _mock.Called(ctx, update)
910 911
911 if len(ret) == 0 {912 if len(ret) == 0 {
@@ -913,7 +914,7 @@ func (_mock *MockEngine) UpdateSettings(ctx context.Context, update port.EngineS
913 }914 }
914 915
915 var r0 error916 var r0 error
916- if returnFunc, ok := ret.Get(0).(func(context.Context, port.EngineSettingsUpdate) error); ok {917+ if returnFunc, ok := ret.Get(0).(func(context.Context, entity.EngineSettingsUpdate) error); ok {
917 r0 = returnFunc(ctx, update)918 r0 = returnFunc(ctx, update)
918 } else {919 } else {
919 r0 = ret.Error(0)920 r0 = ret.Error(0)
@@ -928,20 +929,20 @@ type MockEngine_UpdateSettings_Call struct {
928 929
929 // UpdateSettings is a helper method to define mock.On call930 // UpdateSettings is a helper method to define mock.On call
930 // - ctx context.Context931 // - ctx context.Context
931-// - update port.EngineSettingsUpdate932+// - update entity.EngineSettingsUpdate
932 func (_e *MockEngine_Expecter) UpdateSettings(ctx any, update any) *MockEngine_UpdateSettings_Call {933 func (_e *MockEngine_Expecter) UpdateSettings(ctx any, update any) *MockEngine_UpdateSettings_Call {
933 return &MockEngine_UpdateSettings_Call{Call: _e.mock.On("UpdateSettings", ctx, update)}934 return &MockEngine_UpdateSettings_Call{Call: _e.mock.On("UpdateSettings", ctx, update)}
934 }935 }
935 936
936-func (_c *MockEngine_UpdateSettings_Call) Run(run func(ctx context.Context, update port.EngineSettingsUpdate)) *MockEngine_UpdateSettings_Call {937+func (_c *MockEngine_UpdateSettings_Call) Run(run func(ctx context.Context, update entity.EngineSettingsUpdate)) *MockEngine_UpdateSettings_Call {
937 _c.Call.Run(func(args mock.Arguments) {938 _c.Call.Run(func(args mock.Arguments) {
938 var arg0 context.Context939 var arg0 context.Context
939 if args[0] != nil {940 if args[0] != nil {
940 arg0 = args[0].(context.Context)941 arg0 = args[0].(context.Context)
941 }942 }
942- var arg1 port.EngineSettingsUpdate943+ var arg1 entity.EngineSettingsUpdate
943 if args[1] != nil {944 if args[1] != nil {
944- arg1 = args[1].(port.EngineSettingsUpdate)945+ arg1 = args[1].(entity.EngineSettingsUpdate)
945 }946 }
946 run(947 run(
947 arg0,948 arg0,
@@ -956,7 +957,7 @@ func (_c *MockEngine_UpdateSettings_Call) Return(err error) *MockEngine_UpdateSe
956 return _c957 return _c
957 }958 }
958 959
959-func (_c *MockEngine_UpdateSettings_Call) RunAndReturn(run func(ctx context.Context, update port.EngineSettingsUpdate) error) *MockEngine_UpdateSettings_Call {960+func (_c *MockEngine_UpdateSettings_Call) RunAndReturn(run func(ctx context.Context, update entity.EngineSettingsUpdate) error) *MockEngine_UpdateSettings_Call {
960 _c.Call.Return(run)961 _c.Call.Return(run)
961 return _c962 return _c
962 }963 }
M internal/application/port/mocks/runtime_config.go +13 -13
@@ -5,7 +5,7 @@
55 package mocks
66
77 import (
8- "github.com/bnema/dumber/internal/application/port"
8+ "github.com/bnema/dumber/internal/domain/entity"
99 mock "github.com/stretchr/testify/mock"
1010 )
1111
@@ -37,18 +37,18 @@ func (_m *MockRuntimeConfigProvider) EXPECT() *MockRuntimeConfigProvider_Expecte
3737 }
3838
3939 // Current provides a mock function for the type MockRuntimeConfigProvider
40-func (_mock *MockRuntimeConfigProvider) Current() port.RuntimeConfigSnapshot {
40+func (_mock *MockRuntimeConfigProvider) Current() entity.RuntimeConfigSnapshot {
4141 ret := _mock.Called()
4242
4343 if len(ret) == 0 {
4444 panic("no return value specified for Current")
4545 }
4646
47- var r0 port.RuntimeConfigSnapshot
48- if returnFunc, ok := ret.Get(0).(func() port.RuntimeConfigSnapshot); ok {
47+ var r0 entity.RuntimeConfigSnapshot
48+ if returnFunc, ok := ret.Get(0).(func() entity.RuntimeConfigSnapshot); ok {
4949 r0 = returnFunc()
5050 } else {
51- r0 = ret.Get(0).(port.RuntimeConfigSnapshot)
51+ r0 = ret.Get(0).(entity.RuntimeConfigSnapshot)
5252 }
5353 return r0
5454 }
@@ -70,18 +70,18 @@ func (_c *MockRuntimeConfigProvider_Current_Call) Run(run func()) *MockRuntimeCo
7070 return _c
7171 }
7272
73-func (_c *MockRuntimeConfigProvider_Current_Call) Return(runtimeConfigSnapshot port.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {
73+func (_c *MockRuntimeConfigProvider_Current_Call) Return(runtimeConfigSnapshot entity.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {
7474 _c.Call.Return(runtimeConfigSnapshot)
7575 return _c
7676 }
7777
78-func (_c *MockRuntimeConfigProvider_Current_Call) RunAndReturn(run func() port.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {
78+func (_c *MockRuntimeConfigProvider_Current_Call) RunAndReturn(run func() entity.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {
7979 _c.Call.Return(run)
8080 return _c
8181 }
8282
8383 // OnChange provides a mock function for the type MockRuntimeConfigProvider
84-func (_mock *MockRuntimeConfigProvider) OnChange(fn func(port.RuntimeConfigSnapshot)) {
84+func (_mock *MockRuntimeConfigProvider) OnChange(fn func(entity.RuntimeConfigSnapshot)) {
8585 _mock.Called(fn)
8686 return
8787 }
@@ -92,16 +92,16 @@ type MockRuntimeConfigProvider_OnChange_Call struct {
9292 }
9393
9494 // OnChange is a helper method to define mock.On call
95-// - fn func(port.RuntimeConfigSnapshot)
95+// - fn func(entity.RuntimeConfigSnapshot)
9696 func (_e *MockRuntimeConfigProvider_Expecter) OnChange(fn any) *MockRuntimeConfigProvider_OnChange_Call {
9797 return &MockRuntimeConfigProvider_OnChange_Call{Call: _e.mock.On("OnChange", fn)}
9898 }
9999
100-func (_c *MockRuntimeConfigProvider_OnChange_Call) Run(run func(fn func(port.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {
100+func (_c *MockRuntimeConfigProvider_OnChange_Call) Run(run func(fn func(entity.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {
101101 _c.Call.Run(func(args mock.Arguments) {
102- var arg0 func(port.RuntimeConfigSnapshot)
102+ var arg0 func(entity.RuntimeConfigSnapshot)
103103 if args[0] != nil {
104- arg0 = args[0].(func(port.RuntimeConfigSnapshot))
104+ arg0 = args[0].(func(entity.RuntimeConfigSnapshot))
105105 }
106106 run(
107107 arg0,
@@ -115,7 +115,7 @@ func (_c *MockRuntimeConfigProvider_OnChange_Call) Return() *MockRuntimeConfigPr
115115 return _c
116116 }
117117
118-func (_c *MockRuntimeConfigProvider_OnChange_Call) RunAndReturn(run func(fn func(port.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {
118+func (_c *MockRuntimeConfigProvider_OnChange_Call) RunAndReturn(run func(fn func(entity.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {
119119 _c.Run(run)
120120 return _c
121121 }
@@ -5,7 +5,7 @@
5 package mocks5 package mocks
6 6
7 import (7 import (
8- "github.com/bnema/dumber/internal/application/port"8+ "github.com/bnema/dumber/internal/domain/entity"
9 mock "github.com/stretchr/testify/mock"9 mock "github.com/stretchr/testify/mock"
10 )10 )
11 11
@@ -37,18 +37,18 @@ func (_m *MockRuntimeConfigProvider) EXPECT() *MockRuntimeConfigProvider_Expecte
37 }37 }
38 38
39 // Current provides a mock function for the type MockRuntimeConfigProvider39 // Current provides a mock function for the type MockRuntimeConfigProvider
40-func (_mock *MockRuntimeConfigProvider) Current() port.RuntimeConfigSnapshot {40+func (_mock *MockRuntimeConfigProvider) Current() entity.RuntimeConfigSnapshot {
41 ret := _mock.Called()41 ret := _mock.Called()
42 42
43 if len(ret) == 0 {43 if len(ret) == 0 {
44 panic("no return value specified for Current")44 panic("no return value specified for Current")
45 }45 }
46 46
47- var r0 port.RuntimeConfigSnapshot47+ var r0 entity.RuntimeConfigSnapshot
48- if returnFunc, ok := ret.Get(0).(func() port.RuntimeConfigSnapshot); ok {48+ if returnFunc, ok := ret.Get(0).(func() entity.RuntimeConfigSnapshot); ok {
49 r0 = returnFunc()49 r0 = returnFunc()
50 } else {50 } else {
51- r0 = ret.Get(0).(port.RuntimeConfigSnapshot)51+ r0 = ret.Get(0).(entity.RuntimeConfigSnapshot)
52 }52 }
53 return r053 return r0
54 }54 }
@@ -70,18 +70,18 @@ func (_c *MockRuntimeConfigProvider_Current_Call) Run(run func()) *MockRuntimeCo
70 return _c70 return _c
71 }71 }
72 72
73-func (_c *MockRuntimeConfigProvider_Current_Call) Return(runtimeConfigSnapshot port.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {73+func (_c *MockRuntimeConfigProvider_Current_Call) Return(runtimeConfigSnapshot entity.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {
74 _c.Call.Return(runtimeConfigSnapshot)74 _c.Call.Return(runtimeConfigSnapshot)
75 return _c75 return _c
76 }76 }
77 77
78-func (_c *MockRuntimeConfigProvider_Current_Call) RunAndReturn(run func() port.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {78+func (_c *MockRuntimeConfigProvider_Current_Call) RunAndReturn(run func() entity.RuntimeConfigSnapshot) *MockRuntimeConfigProvider_Current_Call {
79 _c.Call.Return(run)79 _c.Call.Return(run)
80 return _c80 return _c
81 }81 }
82 82
83 // OnChange provides a mock function for the type MockRuntimeConfigProvider83 // OnChange provides a mock function for the type MockRuntimeConfigProvider
84-func (_mock *MockRuntimeConfigProvider) OnChange(fn func(port.RuntimeConfigSnapshot)) {84+func (_mock *MockRuntimeConfigProvider) OnChange(fn func(entity.RuntimeConfigSnapshot)) {
85 _mock.Called(fn)85 _mock.Called(fn)
86 return86 return
87 }87 }
@@ -92,16 +92,16 @@ type MockRuntimeConfigProvider_OnChange_Call struct {
92 }92 }
93 93
94 // OnChange is a helper method to define mock.On call94 // OnChange is a helper method to define mock.On call
95-// - fn func(port.RuntimeConfigSnapshot)95+// - fn func(entity.RuntimeConfigSnapshot)
96 func (_e *MockRuntimeConfigProvider_Expecter) OnChange(fn any) *MockRuntimeConfigProvider_OnChange_Call {96 func (_e *MockRuntimeConfigProvider_Expecter) OnChange(fn any) *MockRuntimeConfigProvider_OnChange_Call {
97 return &MockRuntimeConfigProvider_OnChange_Call{Call: _e.mock.On("OnChange", fn)}97 return &MockRuntimeConfigProvider_OnChange_Call{Call: _e.mock.On("OnChange", fn)}
98 }98 }
99 99
100-func (_c *MockRuntimeConfigProvider_OnChange_Call) Run(run func(fn func(port.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {100+func (_c *MockRuntimeConfigProvider_OnChange_Call) Run(run func(fn func(entity.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {
101 _c.Call.Run(func(args mock.Arguments) {101 _c.Call.Run(func(args mock.Arguments) {
102- var arg0 func(port.RuntimeConfigSnapshot)102+ var arg0 func(entity.RuntimeConfigSnapshot)
103 if args[0] != nil {103 if args[0] != nil {
104- arg0 = args[0].(func(port.RuntimeConfigSnapshot))104+ arg0 = args[0].(func(entity.RuntimeConfigSnapshot))
105 }105 }
106 run(106 run(
107 arg0,107 arg0,
@@ -115,7 +115,7 @@ func (_c *MockRuntimeConfigProvider_OnChange_Call) Return() *MockRuntimeConfigPr
115 return _c115 return _c
116 }116 }
117 117
118-func (_c *MockRuntimeConfigProvider_OnChange_Call) RunAndReturn(run func(fn func(port.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {118+func (_c *MockRuntimeConfigProvider_OnChange_Call) RunAndReturn(run func(fn func(entity.RuntimeConfigSnapshot))) *MockRuntimeConfigProvider_OnChange_Call {
119 _c.Run(run)119 _c.Run(run)
120 return _c120 return _c
121 }121 }
M internal/application/port/runtime_config.go +2 -46
@@ -3,51 +3,7 @@ package port
33 import "github.com/bnema/dumber/internal/domain/entity"
44
55 type RuntimeConfigProvider interface {
6- Current() RuntimeConfigSnapshot
6+ Current() entity.RuntimeConfigSnapshot
77 Watch() error
8- OnChange(func(RuntimeConfigSnapshot))
9-}
10-
11-type RuntimeConfigSnapshot struct {
12- EngineSettings EngineSettingsPayload
13- UI RuntimeUIConfig
14-}
15-
16-type RuntimeUIConfig struct {
17- DefaultUIScale float64
18- SidebarWidth int
19- Appearance entity.AppearanceConfig
20- Workspace entity.WorkspaceConfig
21- Session entity.SessionConfig
22- Clipboard RuntimeClipboardConfig
23- SearchShortcuts map[string]RuntimeSearchShortcut
24- DefaultSearchEngine string
25- Omnibox RuntimeOmniboxConfig
26- Update RuntimeUpdateConfig
27- Downloads RuntimeDownloadsConfig
28-}
29-
30-type RuntimeClipboardConfig struct {
31- AutoCopyOnSelection bool
32-}
33-
34-type RuntimeSearchShortcut struct {
35- URL string
36- Description string
37-}
38-
39-type RuntimeOmniboxConfig struct {
40- InitialBehavior entity.OmniboxInitialBehavior
41- MostVisitedDays int
42- AutoOpenOnNewPane bool
43-}
44-
45-type RuntimeUpdateConfig struct {
46- EnableOnStartup bool
47- AutoDownload bool
48- NotifyOnNewSettings bool
49-}
50-
51-type RuntimeDownloadsConfig struct {
52- Path string
8+ OnChange(func(entity.RuntimeConfigSnapshot))
539 }
@@ -3,51 +3,7 @@ package port
3 import "github.com/bnema/dumber/internal/domain/entity"3 import "github.com/bnema/dumber/internal/domain/entity"
4 4
5 type RuntimeConfigProvider interface {5 type RuntimeConfigProvider interface {
6- Current() RuntimeConfigSnapshot6+ Current() entity.RuntimeConfigSnapshot
7 Watch() error7 Watch() error
8- OnChange(func(RuntimeConfigSnapshot))8+ OnChange(func(entity.RuntimeConfigSnapshot))
9-}
10-
11-type RuntimeConfigSnapshot struct {
12- EngineSettings EngineSettingsPayload
13- UI RuntimeUIConfig
14-}
15-
16-type RuntimeUIConfig struct {
17- DefaultUIScale float64
18- SidebarWidth int
19- Appearance entity.AppearanceConfig
20- Workspace entity.WorkspaceConfig
21- Session entity.SessionConfig
22- Clipboard RuntimeClipboardConfig
23- SearchShortcuts map[string]RuntimeSearchShortcut
24- DefaultSearchEngine string
25- Omnibox RuntimeOmniboxConfig
26- Update RuntimeUpdateConfig
27- Downloads RuntimeDownloadsConfig
28-}
29-
30-type RuntimeClipboardConfig struct {
31- AutoCopyOnSelection bool
32-}
33-
34-type RuntimeSearchShortcut struct {
35- URL string
36- Description string
37-}
38-
39-type RuntimeOmniboxConfig struct {
40- InitialBehavior entity.OmniboxInitialBehavior
41- MostVisitedDays int
42- AutoOpenOnNewPane bool
43-}
44-
45-type RuntimeUpdateConfig struct {
46- EnableOnStartup bool
47- AutoDownload bool
48- NotifyOnNewSettings bool
49-}
50-
51-type RuntimeDownloadsConfig struct {
52- Path string
53 }9 }
M internal/bootstrap/runtime_config.go +35 -27
@@ -13,7 +13,7 @@ type configChangeManager interface {
1313 }
1414
1515 type runtimeConfigProvider struct {
16- fallback port.RuntimeConfigSnapshot
16+ fallback entity.RuntimeConfigSnapshot
1717 manager configChangeManager
1818 }
1919
@@ -24,14 +24,18 @@ func NewRuntimeConfigProvider(cfg *config.Config, manager configChangeManager) p
2424 }
2525 }
2626
27-func (p *runtimeConfigProvider) Current() port.RuntimeConfigSnapshot {
27+func (p *runtimeConfigProvider) Current() entity.RuntimeConfigSnapshot {
2828 if p == nil {
29- return port.RuntimeConfigSnapshot{}
29+ return entity.RuntimeConfigSnapshot{}
3030 }
3131 if p.manager == nil {
3232 return cloneRuntimeConfigSnapshot(p.fallback)
3333 }
34- return RuntimeConfigSnapshotFromConfig(p.manager.Get())
34+ cfg := p.manager.Get()
35+ if cfg == nil {
36+ return cloneRuntimeConfigSnapshot(p.fallback)
37+ }
38+ return RuntimeConfigSnapshotFromConfig(cfg)
3539 }
3640
3741 func (p *runtimeConfigProvider) Watch() error {
@@ -41,22 +45,26 @@ func (p *runtimeConfigProvider) Watch() error {
4145 return p.manager.Watch()
4246 }
4347
44-func (p *runtimeConfigProvider) OnChange(callback func(port.RuntimeConfigSnapshot)) {
48+func (p *runtimeConfigProvider) OnChange(callback func(entity.RuntimeConfigSnapshot)) {
4549 if p == nil || p.manager == nil || callback == nil {
4650 return
4751 }
4852 p.manager.OnConfigChange(func(cfg *config.Config) {
53+ if cfg == nil {
54+ callback(cloneRuntimeConfigSnapshot(p.fallback))
55+ return
56+ }
4957 callback(RuntimeConfigSnapshotFromConfig(cfg))
5058 })
5159 }
5260
53-func EngineSettingsPayloadFromConfig(cfg *config.Config) port.EngineSettingsPayload {
61+func EngineSettingsPayloadFromConfig(cfg *config.Config) entity.EngineSettingsPayload {
5462 if cfg == nil {
55- return port.EngineSettingsPayload{}
63+ return entity.EngineSettingsPayload{}
5664 }
57- return port.EngineSettingsPayload{
65+ return entity.EngineSettingsPayload{
5866 DefaultUIScale: cfg.DefaultUIScale,
59- WebContent: port.EngineWebContentSettingsPayload{
67+ WebContent: entity.EngineWebContentSettingsPayload{
6068 SansFont: cfg.Appearance.SansFont,
6169 SerifFont: cfg.Appearance.SerifFont,
6270 MonospaceFont: cfg.Appearance.MonospaceFont,
@@ -70,40 +78,40 @@ func EngineSettingsPayloadFromConfig(cfg *config.Config) port.EngineSettingsPayl
7078 }
7179 }
7280
73-func RuntimeConfigSnapshotFromConfig(cfg *config.Config) port.RuntimeConfigSnapshot {
81+func RuntimeConfigSnapshotFromConfig(cfg *config.Config) entity.RuntimeConfigSnapshot {
7482 if cfg == nil {
75- return port.RuntimeConfigSnapshot{}
83+ return entity.RuntimeConfigSnapshot{}
7684 }
77- return port.RuntimeConfigSnapshot{
85+ return entity.RuntimeConfigSnapshot{
7886 EngineSettings: EngineSettingsPayloadFromConfig(cfg),
79- UI: port.RuntimeUIConfig{
87+ UI: entity.RuntimeUIConfig{
8088 DefaultUIScale: cfg.DefaultUIScale,
8189 SidebarWidth: cfg.SidebarWidth,
8290 Appearance: cfg.Appearance,
8391 Workspace: cloneWorkspaceConfig(cfg.Workspace),
8492 Session: cloneSessionConfig(cfg.Session),
85- Clipboard: port.RuntimeClipboardConfig{AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection},
93+ Clipboard: entity.RuntimeClipboardConfig{AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection},
8694 SearchShortcuts: runtimeSearchShortcutsFromConfig(cfg.SearchShortcuts),
8795 DefaultSearchEngine: cfg.DefaultSearchEngine,
88- Omnibox: port.RuntimeOmniboxConfig{
96+ Omnibox: entity.RuntimeOmniboxConfig{
8997 InitialBehavior: cfg.Omnibox.InitialBehavior,
9098 MostVisitedDays: cfg.Omnibox.MostVisitedDays,
9199 AutoOpenOnNewPane: cfg.Omnibox.AutoOpenOnNewPane,
92100 },
93- Update: port.RuntimeUpdateConfig{
101+ Update: entity.RuntimeUpdateConfig{
94102 EnableOnStartup: cfg.Update.EnableOnStartup,
95103 AutoDownload: cfg.Update.AutoDownload,
96104 NotifyOnNewSettings: cfg.Update.NotifyOnNewSettings,
97105 },
98- Downloads: port.RuntimeDownloadsConfig{Path: cfg.Downloads.Path},
106+ Downloads: entity.RuntimeDownloadsConfig{Path: cfg.Downloads.Path},
99107 },
100108 }
101109 }
102110
103-func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[string]port.RuntimeSearchShortcut {
104- out := make(map[string]port.RuntimeSearchShortcut, len(in))
111+func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[string]entity.RuntimeSearchShortcut {
112+ out := make(map[string]entity.RuntimeSearchShortcut, len(in))
105113 for key, shortcut := range in {
106- out[key] = port.RuntimeSearchShortcut{
114+ out[key] = entity.RuntimeSearchShortcut{
107115 URL: shortcut.URL,
108116 Description: shortcut.Description,
109117 }
@@ -111,18 +119,18 @@ func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[s
111119 return out
112120 }
113121
114-func cloneRuntimeConfigSnapshot(snapshot port.RuntimeConfigSnapshot) port.RuntimeConfigSnapshot {
122+func cloneRuntimeConfigSnapshot(snapshot entity.RuntimeConfigSnapshot) entity.RuntimeConfigSnapshot {
115123 snapshot.UI.SearchShortcuts = cloneRuntimeSearchShortcuts(snapshot.UI.SearchShortcuts)
116124 snapshot.UI.Workspace = cloneWorkspaceConfig(snapshot.UI.Workspace)
117125 snapshot.UI.Session = cloneSessionConfig(snapshot.UI.Session)
118126 return snapshot
119127 }
120128
121-func cloneRuntimeSearchShortcuts(in map[string]port.RuntimeSearchShortcut) map[string]port.RuntimeSearchShortcut {
129+func cloneRuntimeSearchShortcuts(in map[string]entity.RuntimeSearchShortcut) map[string]entity.RuntimeSearchShortcut {
122130 if in == nil {
123131 return nil
124132 }
125- out := make(map[string]port.RuntimeSearchShortcut, len(in))
133+ out := make(map[string]entity.RuntimeSearchShortcut, len(in))
126134 for key, shortcut := range in {
127135 out[key] = shortcut
128136 }
@@ -176,13 +184,13 @@ func cloneStringSlice(in []string) []string {
176184 return out
177185 }
178186
179-func engineHardwareDecodingModeFromConfig(mode config.HardwareDecodingMode) port.EngineHardwareDecodingMode {
187+func engineHardwareDecodingModeFromConfig(mode config.HardwareDecodingMode) entity.EngineHardwareDecodingMode {
180188 switch mode {
181189 case config.HardwareDecodingForce:
182- return port.EngineHardwareDecodingForce
190+ return entity.EngineHardwareDecodingForce
183191 case config.HardwareDecodingDisable:
184- return port.EngineHardwareDecodingDisable
192+ return entity.EngineHardwareDecodingDisable
185193 default:
186- return port.EngineHardwareDecodingAuto
194+ return entity.EngineHardwareDecodingAuto
187195 }
188196 }
@@ -13,7 +13,7 @@ type configChangeManager interface {
13 }13 }
14 14
15 type runtimeConfigProvider struct {15 type runtimeConfigProvider struct {
16- fallback port.RuntimeConfigSnapshot16+ fallback entity.RuntimeConfigSnapshot
17 manager configChangeManager17 manager configChangeManager
18 }18 }
19 19
@@ -24,14 +24,18 @@ func NewRuntimeConfigProvider(cfg *config.Config, manager configChangeManager) p
24 }24 }
25 }25 }
26 26
27-func (p *runtimeConfigProvider) Current() port.RuntimeConfigSnapshot {27+func (p *runtimeConfigProvider) Current() entity.RuntimeConfigSnapshot {
28 if p == nil {28 if p == nil {
29- return port.RuntimeConfigSnapshot{}29+ return entity.RuntimeConfigSnapshot{}
30 }30 }
31 if p.manager == nil {31 if p.manager == nil {
32 return cloneRuntimeConfigSnapshot(p.fallback)32 return cloneRuntimeConfigSnapshot(p.fallback)
33 }33 }
34- return RuntimeConfigSnapshotFromConfig(p.manager.Get())34+ cfg := p.manager.Get()
35+ if cfg == nil {
36+ return cloneRuntimeConfigSnapshot(p.fallback)
37+ }
38+ return RuntimeConfigSnapshotFromConfig(cfg)
35 }39 }
36 40
37 func (p *runtimeConfigProvider) Watch() error {41 func (p *runtimeConfigProvider) Watch() error {
@@ -41,22 +45,26 @@ func (p *runtimeConfigProvider) Watch() error {
41 return p.manager.Watch()45 return p.manager.Watch()
42 }46 }
43 47
44-func (p *runtimeConfigProvider) OnChange(callback func(port.RuntimeConfigSnapshot)) {48+func (p *runtimeConfigProvider) OnChange(callback func(entity.RuntimeConfigSnapshot)) {
45 if p == nil || p.manager == nil || callback == nil {49 if p == nil || p.manager == nil || callback == nil {
46 return50 return
47 }51 }
48 p.manager.OnConfigChange(func(cfg *config.Config) {52 p.manager.OnConfigChange(func(cfg *config.Config) {
53+ if cfg == nil {
54+ callback(cloneRuntimeConfigSnapshot(p.fallback))
55+ return
56+ }
49 callback(RuntimeConfigSnapshotFromConfig(cfg))57 callback(RuntimeConfigSnapshotFromConfig(cfg))
50 })58 })
51 }59 }
52 60
53-func EngineSettingsPayloadFromConfig(cfg *config.Config) port.EngineSettingsPayload {61+func EngineSettingsPayloadFromConfig(cfg *config.Config) entity.EngineSettingsPayload {
54 if cfg == nil {62 if cfg == nil {
55- return port.EngineSettingsPayload{}63+ return entity.EngineSettingsPayload{}
56 }64 }
57- return port.EngineSettingsPayload{65+ return entity.EngineSettingsPayload{
58 DefaultUIScale: cfg.DefaultUIScale,66 DefaultUIScale: cfg.DefaultUIScale,
59- WebContent: port.EngineWebContentSettingsPayload{67+ WebContent: entity.EngineWebContentSettingsPayload{
60 SansFont: cfg.Appearance.SansFont,68 SansFont: cfg.Appearance.SansFont,
61 SerifFont: cfg.Appearance.SerifFont,69 SerifFont: cfg.Appearance.SerifFont,
62 MonospaceFont: cfg.Appearance.MonospaceFont,70 MonospaceFont: cfg.Appearance.MonospaceFont,
@@ -70,40 +78,40 @@ func EngineSettingsPayloadFromConfig(cfg *config.Config) port.EngineSettingsPayl
70 }78 }
71 }79 }
72 80
73-func RuntimeConfigSnapshotFromConfig(cfg *config.Config) port.RuntimeConfigSnapshot {81+func RuntimeConfigSnapshotFromConfig(cfg *config.Config) entity.RuntimeConfigSnapshot {
74 if cfg == nil {82 if cfg == nil {
75- return port.RuntimeConfigSnapshot{}83+ return entity.RuntimeConfigSnapshot{}
76 }84 }
77- return port.RuntimeConfigSnapshot{85+ return entity.RuntimeConfigSnapshot{
78 EngineSettings: EngineSettingsPayloadFromConfig(cfg),86 EngineSettings: EngineSettingsPayloadFromConfig(cfg),
79- UI: port.RuntimeUIConfig{87+ UI: entity.RuntimeUIConfig{
80 DefaultUIScale: cfg.DefaultUIScale,88 DefaultUIScale: cfg.DefaultUIScale,
81 SidebarWidth: cfg.SidebarWidth,89 SidebarWidth: cfg.SidebarWidth,
82 Appearance: cfg.Appearance,90 Appearance: cfg.Appearance,
83 Workspace: cloneWorkspaceConfig(cfg.Workspace),91 Workspace: cloneWorkspaceConfig(cfg.Workspace),
84 Session: cloneSessionConfig(cfg.Session),92 Session: cloneSessionConfig(cfg.Session),
85- Clipboard: port.RuntimeClipboardConfig{AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection},93+ Clipboard: entity.RuntimeClipboardConfig{AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection},
86 SearchShortcuts: runtimeSearchShortcutsFromConfig(cfg.SearchShortcuts),94 SearchShortcuts: runtimeSearchShortcutsFromConfig(cfg.SearchShortcuts),
87 DefaultSearchEngine: cfg.DefaultSearchEngine,95 DefaultSearchEngine: cfg.DefaultSearchEngine,
88- Omnibox: port.RuntimeOmniboxConfig{96+ Omnibox: entity.RuntimeOmniboxConfig{
89 InitialBehavior: cfg.Omnibox.InitialBehavior,97 InitialBehavior: cfg.Omnibox.InitialBehavior,
90 MostVisitedDays: cfg.Omnibox.MostVisitedDays,98 MostVisitedDays: cfg.Omnibox.MostVisitedDays,
91 AutoOpenOnNewPane: cfg.Omnibox.AutoOpenOnNewPane,99 AutoOpenOnNewPane: cfg.Omnibox.AutoOpenOnNewPane,
92 },100 },
93- Update: port.RuntimeUpdateConfig{101+ Update: entity.RuntimeUpdateConfig{
94 EnableOnStartup: cfg.Update.EnableOnStartup,102 EnableOnStartup: cfg.Update.EnableOnStartup,
95 AutoDownload: cfg.Update.AutoDownload,103 AutoDownload: cfg.Update.AutoDownload,
96 NotifyOnNewSettings: cfg.Update.NotifyOnNewSettings,104 NotifyOnNewSettings: cfg.Update.NotifyOnNewSettings,
97 },105 },
98- Downloads: port.RuntimeDownloadsConfig{Path: cfg.Downloads.Path},106+ Downloads: entity.RuntimeDownloadsConfig{Path: cfg.Downloads.Path},
99 },107 },
100 }108 }
101 }109 }
102 110
103-func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[string]port.RuntimeSearchShortcut {111+func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[string]entity.RuntimeSearchShortcut {
104- out := make(map[string]port.RuntimeSearchShortcut, len(in))112+ out := make(map[string]entity.RuntimeSearchShortcut, len(in))
105 for key, shortcut := range in {113 for key, shortcut := range in {
106- out[key] = port.RuntimeSearchShortcut{114+ out[key] = entity.RuntimeSearchShortcut{
107 URL: shortcut.URL,115 URL: shortcut.URL,
108 Description: shortcut.Description,116 Description: shortcut.Description,
109 }117 }
@@ -111,18 +119,18 @@ func runtimeSearchShortcutsFromConfig(in map[string]config.SearchShortcut) map[s
111 return out119 return out
112 }120 }
113 121
114-func cloneRuntimeConfigSnapshot(snapshot port.RuntimeConfigSnapshot) port.RuntimeConfigSnapshot {122+func cloneRuntimeConfigSnapshot(snapshot entity.RuntimeConfigSnapshot) entity.RuntimeConfigSnapshot {
115 snapshot.UI.SearchShortcuts = cloneRuntimeSearchShortcuts(snapshot.UI.SearchShortcuts)123 snapshot.UI.SearchShortcuts = cloneRuntimeSearchShortcuts(snapshot.UI.SearchShortcuts)
116 snapshot.UI.Workspace = cloneWorkspaceConfig(snapshot.UI.Workspace)124 snapshot.UI.Workspace = cloneWorkspaceConfig(snapshot.UI.Workspace)
117 snapshot.UI.Session = cloneSessionConfig(snapshot.UI.Session)125 snapshot.UI.Session = cloneSessionConfig(snapshot.UI.Session)
118 return snapshot126 return snapshot
119 }127 }
120 128
121-func cloneRuntimeSearchShortcuts(in map[string]port.RuntimeSearchShortcut) map[string]port.RuntimeSearchShortcut {129+func cloneRuntimeSearchShortcuts(in map[string]entity.RuntimeSearchShortcut) map[string]entity.RuntimeSearchShortcut {
122 if in == nil {130 if in == nil {
123 return nil131 return nil
124 }132 }
125- out := make(map[string]port.RuntimeSearchShortcut, len(in))133+ out := make(map[string]entity.RuntimeSearchShortcut, len(in))
126 for key, shortcut := range in {134 for key, shortcut := range in {
127 out[key] = shortcut135 out[key] = shortcut
128 }136 }
@@ -176,13 +184,13 @@ func cloneStringSlice(in []string) []string {
176 return out184 return out
177 }185 }
178 186
179-func engineHardwareDecodingModeFromConfig(mode config.HardwareDecodingMode) port.EngineHardwareDecodingMode {187+func engineHardwareDecodingModeFromConfig(mode config.HardwareDecodingMode) entity.EngineHardwareDecodingMode {
180 switch mode {188 switch mode {
181 case config.HardwareDecodingForce:189 case config.HardwareDecodingForce:
182- return port.EngineHardwareDecodingForce190+ return entity.EngineHardwareDecodingForce
183 case config.HardwareDecodingDisable:191 case config.HardwareDecodingDisable:
184- return port.EngineHardwareDecodingDisable192+ return entity.EngineHardwareDecodingDisable
185 default:193 default:
186- return port.EngineHardwareDecodingAuto194+ return entity.EngineHardwareDecodingAuto
187 }195 }
188 }196 }
M internal/bootstrap/runtime_config_test.go +52 -20
@@ -4,7 +4,6 @@ import (
44 "reflect"
55 "testing"
66
7- "github.com/bnema/dumber/internal/application/port"
87 bootstrapmocks "github.com/bnema/dumber/internal/bootstrap/mocks"
98 "github.com/bnema/dumber/internal/domain/entity"
109 "github.com/bnema/dumber/internal/infrastructure/config"
@@ -76,8 +75,8 @@ func TestEngineSettingsPayloadFromConfigMapsRuntimeFields(t *testing.T) {
7675 !got.WebContent.DrawCompositingIndicators {
7776 t.Fatalf("debug settings not mapped: %#v", got.WebContent)
7877 }
79- if got.WebContent.HardwareDecoding != port.EngineHardwareDecodingForce {
80- t.Fatalf("HardwareDecoding=%q, want %q", got.WebContent.HardwareDecoding, port.EngineHardwareDecodingForce)
78+ if got.WebContent.HardwareDecoding != entity.EngineHardwareDecodingForce {
79+ t.Fatalf("HardwareDecoding=%q, want %q", got.WebContent.HardwareDecoding, entity.EngineHardwareDecodingForce)
8180 }
8281 autoCopyField := reflect.ValueOf(got.WebContent).FieldByName("AutoCopyOnSelection")
8382 if !autoCopyField.IsValid() || !autoCopyField.Bool() {
@@ -91,8 +90,8 @@ func TestRuntimeConfigProviderUpdatesSnapshotBeforeCallback(t *testing.T) {
9190 manager := &configManagerState{}
9291 provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
9392
94- var seen port.RuntimeConfigSnapshot
95- provider.OnChange(func(snapshot port.RuntimeConfigSnapshot) {
93+ var seen entity.RuntimeConfigSnapshot
94+ provider.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
9695 seen = snapshot
9796 })
9897
@@ -123,6 +122,20 @@ func TestRuntimeConfigProviderCurrentReflectsManagerGetWithoutSubscription(t *te
123122 }
124123 }
125124
125+func TestRuntimeConfigProviderCurrentFallsBackWhenManagerGetReturnsNil(t *testing.T) {
126+ initial := config.DefaultConfig()
127+ initial.DefaultUIScale = 1.35
128+ manager := &configManagerState{}
129+ provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
130+
131+ got := provider.Current()
132+ want := RuntimeConfigSnapshotFromConfig(initial)
133+
134+ if !reflect.DeepEqual(got, want) {
135+ t.Fatalf("Current()=%#v, want initial fallback %#v", got, want)
136+ }
137+}
138+
126139 func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {
127140 initial := config.DefaultConfig()
128141 initial.DefaultUIScale = 1
@@ -130,8 +143,8 @@ func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {
130143 provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
131144
132145 completed := false
133- var seen port.RuntimeConfigSnapshot
134- provider.OnChange(func(port.RuntimeConfigSnapshot) {
146+ var seen entity.RuntimeConfigSnapshot
147+ provider.OnChange(func(entity.RuntimeConfigSnapshot) {
135148 seen = provider.Current()
136149 completed = true
137150 })
@@ -148,6 +161,25 @@ func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {
148161 }
149162 }
150163
164+func TestRuntimeConfigProviderOnChangeFallsBackWhenPayloadIsNil(t *testing.T) {
165+ initial := config.DefaultConfig()
166+ initial.DefaultUIScale = 1.35
167+ manager := &configManagerState{current: initial}
168+ provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
169+
170+ var seen entity.RuntimeConfigSnapshot
171+ provider.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
172+ seen = snapshot
173+ })
174+
175+ manager.emit(nil)
176+ want := RuntimeConfigSnapshotFromConfig(initial)
177+
178+ if !reflect.DeepEqual(seen, want) {
179+ t.Fatalf("callback snapshot=%#v, want initial fallback %#v", seen, want)
180+ }
181+}
182+
151183 func TestRuntimeConfigProviderOnChangeNilCallbackDoesNotRegister(t *testing.T) {
152184 manager := &configManagerState{current: config.DefaultConfig()}
153185 provider := NewRuntimeConfigProvider(config.DefaultConfig(), newMockConfigManager(t, manager))
@@ -179,7 +211,7 @@ func TestRuntimeConfigProviderCurrentReturnsMapClone(t *testing.T) {
179211 provider := NewRuntimeConfigProvider(cfg, newMockConfigManager(t, &configManagerState{current: cfg}))
180212
181213 first := provider.Current()
182- first.UI.SearchShortcuts["gh"] = port.RuntimeSearchShortcut{URL: "mutated"}
214+ first.UI.SearchShortcuts["gh"] = entity.RuntimeSearchShortcut{URL: "mutated"}
183215 second := provider.Current()
184216
185217 if second.UI.SearchShortcuts["gh"].URL == "mutated" {
@@ -202,7 +234,7 @@ func TestRuntimeConfigProviderOnChangePassesNestedConfigClone(t *testing.T) {
202234 manager := &configManagerState{}
203235 provider := NewRuntimeConfigProvider(config.DefaultConfig(), newMockConfigManager(t, manager))
204236
205- provider.OnChange(func(snapshot port.RuntimeConfigSnapshot) {
237+ provider.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
206238 mutateNestedRuntimeConfigSnapshot(snapshot)
207239 })
208240
@@ -213,7 +245,7 @@ func TestRuntimeConfigProviderOnChangePassesNestedConfigClone(t *testing.T) {
213245
214246 func TestEngineSettingsPayloadFromNilConfigReturnsZeroPayload(t *testing.T) {
215247 got := EngineSettingsPayloadFromConfig(nil)
216- if got != (port.EngineSettingsPayload{}) {
248+ if got != (entity.EngineSettingsPayload{}) {
217249 t.Fatalf("payload=%#v, want zero value", got)
218250 }
219251 }
@@ -241,7 +273,7 @@ func runtimeConfigWithNestedMutableFields() *config.Config {
241273 return cfg
242274 }
243275
244-func mutateNestedRuntimeConfigSnapshot(snapshot port.RuntimeConfigSnapshot) {
276+func mutateNestedRuntimeConfigSnapshot(snapshot entity.RuntimeConfigSnapshot) {
245277 mutateActionBinding(snapshot.UI.Workspace.PaneMode.Actions, "split-right", "mutated-pane")
246278 snapshot.UI.Workspace.PaneMode.Actions["added-pane"] = entity.ActionBinding{Keys: []string{"added"}}
247279
@@ -269,7 +301,7 @@ func mutateActionBinding(actions map[string]entity.ActionBinding, action, key st
269301 actions[action] = binding
270302 }
271303
272-func assertNestedRuntimeConfigSnapshotUnchanged(t *testing.T, snapshot port.RuntimeConfigSnapshot) {
304+func assertNestedRuntimeConfigSnapshotUnchanged(t *testing.T, snapshot entity.RuntimeConfigSnapshot) {
273305 t.Helper()
274306
275307 assertActionBinding(t, snapshot.UI.Workspace.PaneMode.Actions, "split-right", "r")
@@ -377,7 +409,7 @@ func TestRuntimeConfigSnapshotFromConfigMapsUIRuntimeFields(t *testing.T) {
377409 if got.UI.SearchShortcuts["gh"].URL != "https://github.com/search?q=%s" {
378410 t.Fatalf("search shortcut not mapped: %#v", got.UI.SearchShortcuts)
379411 }
380- got.UI.SearchShortcuts["gh"] = port.RuntimeSearchShortcut{URL: "mutated"}
412+ got.UI.SearchShortcuts["gh"] = entity.RuntimeSearchShortcut{URL: "mutated"}
381413 if cfg.SearchShortcuts["gh"].URL == "mutated" {
382414 t.Fatal("snapshot must deep-copy search shortcut map")
383415 }
@@ -394,7 +426,7 @@ func TestRuntimeConfigSnapshotFromConfigDetachesNestedMutableFields(t *testing.T
394426
395427 func TestRuntimeConfigSnapshotFromNilConfigReturnsZeroSnapshot(t *testing.T) {
396428 got := RuntimeConfigSnapshotFromConfig(nil)
397- if !reflect.DeepEqual(got, port.RuntimeConfigSnapshot{}) {
429+ if !reflect.DeepEqual(got, entity.RuntimeConfigSnapshot{}) {
398430 t.Fatalf("snapshot=%#v, want zero value", got)
399431 }
400432 }
@@ -403,32 +435,32 @@ func TestEngineSettingsPayloadFromConfigMapsHardwareDecodingModes(t *testing.T)
403435 tests := []struct {
404436 name string
405437 mode config.HardwareDecodingMode
406- want port.EngineHardwareDecodingMode
438+ want entity.EngineHardwareDecodingMode
407439 }{
408440 {
409441 name: "auto",
410442 mode: config.HardwareDecodingAuto,
411- want: port.EngineHardwareDecodingAuto,
443+ want: entity.EngineHardwareDecodingAuto,
412444 },
413445 {
414446 name: "force",
415447 mode: config.HardwareDecodingForce,
416- want: port.EngineHardwareDecodingForce,
448+ want: entity.EngineHardwareDecodingForce,
417449 },
418450 {
419451 name: "disable",
420452 mode: config.HardwareDecodingDisable,
421- want: port.EngineHardwareDecodingDisable,
453+ want: entity.EngineHardwareDecodingDisable,
422454 },
423455 {
424456 name: "unknown",
425457 mode: config.HardwareDecodingMode("surprise"),
426- want: port.EngineHardwareDecodingAuto,
458+ want: entity.EngineHardwareDecodingAuto,
427459 },
428460 {
429461 name: "zero value",
430462 mode: "",
431- want: port.EngineHardwareDecodingAuto,
463+ want: entity.EngineHardwareDecodingAuto,
432464 },
433465 }
434466
@@ -4,7 +4,6 @@ import (
4 "reflect"4 "reflect"
5 "testing"5 "testing"
6 6
7- "github.com/bnema/dumber/internal/application/port"
8 bootstrapmocks "github.com/bnema/dumber/internal/bootstrap/mocks"7 bootstrapmocks "github.com/bnema/dumber/internal/bootstrap/mocks"
9 "github.com/bnema/dumber/internal/domain/entity"8 "github.com/bnema/dumber/internal/domain/entity"
10 "github.com/bnema/dumber/internal/infrastructure/config"9 "github.com/bnema/dumber/internal/infrastructure/config"
@@ -76,8 +75,8 @@ func TestEngineSettingsPayloadFromConfigMapsRuntimeFields(t *testing.T) {
76 !got.WebContent.DrawCompositingIndicators {75 !got.WebContent.DrawCompositingIndicators {
77 t.Fatalf("debug settings not mapped: %#v", got.WebContent)76 t.Fatalf("debug settings not mapped: %#v", got.WebContent)
78 }77 }
79- if got.WebContent.HardwareDecoding != port.EngineHardwareDecodingForce {78+ if got.WebContent.HardwareDecoding != entity.EngineHardwareDecodingForce {
80- t.Fatalf("HardwareDecoding=%q, want %q", got.WebContent.HardwareDecoding, port.EngineHardwareDecodingForce)79+ t.Fatalf("HardwareDecoding=%q, want %q", got.WebContent.HardwareDecoding, entity.EngineHardwareDecodingForce)
81 }80 }
82 autoCopyField := reflect.ValueOf(got.WebContent).FieldByName("AutoCopyOnSelection")81 autoCopyField := reflect.ValueOf(got.WebContent).FieldByName("AutoCopyOnSelection")
83 if !autoCopyField.IsValid() || !autoCopyField.Bool() {82 if !autoCopyField.IsValid() || !autoCopyField.Bool() {
@@ -91,8 +90,8 @@ func TestRuntimeConfigProviderUpdatesSnapshotBeforeCallback(t *testing.T) {
91 manager := &configManagerState{}90 manager := &configManagerState{}
92 provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))91 provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
93 92
94- var seen port.RuntimeConfigSnapshot93+ var seen entity.RuntimeConfigSnapshot
95- provider.OnChange(func(snapshot port.RuntimeConfigSnapshot) {94+ provider.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
96 seen = snapshot95 seen = snapshot
97 })96 })
98 97
@@ -123,6 +122,20 @@ func TestRuntimeConfigProviderCurrentReflectsManagerGetWithoutSubscription(t *te
123 }122 }
124 }123 }
125 124
125+func TestRuntimeConfigProviderCurrentFallsBackWhenManagerGetReturnsNil(t *testing.T) {
126+ initial := config.DefaultConfig()
127+ initial.DefaultUIScale = 1.35
128+ manager := &configManagerState{}
129+ provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
130+
131+ got := provider.Current()
132+ want := RuntimeConfigSnapshotFromConfig(initial)
133+
134+ if !reflect.DeepEqual(got, want) {
135+ t.Fatalf("Current()=%#v, want initial fallback %#v", got, want)
136+ }
137+}
138+
126 func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {139 func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {
127 initial := config.DefaultConfig()140 initial := config.DefaultConfig()
128 initial.DefaultUIScale = 1141 initial.DefaultUIScale = 1
@@ -130,8 +143,8 @@ func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {
130 provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))143 provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
131 144
132 completed := false145 completed := false
133- var seen port.RuntimeConfigSnapshot146+ var seen entity.RuntimeConfigSnapshot
134- provider.OnChange(func(port.RuntimeConfigSnapshot) {147+ provider.OnChange(func(entity.RuntimeConfigSnapshot) {
135 seen = provider.Current()148 seen = provider.Current()
136 completed = true149 completed = true
137 })150 })
@@ -148,6 +161,25 @@ func TestRuntimeConfigProviderOnChangeCallbackCanCallCurrent(t *testing.T) {
148 }161 }
149 }162 }
150 163
164+func TestRuntimeConfigProviderOnChangeFallsBackWhenPayloadIsNil(t *testing.T) {
165+ initial := config.DefaultConfig()
166+ initial.DefaultUIScale = 1.35
167+ manager := &configManagerState{current: initial}
168+ provider := NewRuntimeConfigProvider(initial, newMockConfigManager(t, manager))
169+
170+ var seen entity.RuntimeConfigSnapshot
171+ provider.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
172+ seen = snapshot
173+ })
174+
175+ manager.emit(nil)
176+ want := RuntimeConfigSnapshotFromConfig(initial)
177+
178+ if !reflect.DeepEqual(seen, want) {
179+ t.Fatalf("callback snapshot=%#v, want initial fallback %#v", seen, want)
180+ }
181+}
182+
151 func TestRuntimeConfigProviderOnChangeNilCallbackDoesNotRegister(t *testing.T) {183 func TestRuntimeConfigProviderOnChangeNilCallbackDoesNotRegister(t *testing.T) {
152 manager := &configManagerState{current: config.DefaultConfig()}184 manager := &configManagerState{current: config.DefaultConfig()}
153 provider := NewRuntimeConfigProvider(config.DefaultConfig(), newMockConfigManager(t, manager))185 provider := NewRuntimeConfigProvider(config.DefaultConfig(), newMockConfigManager(t, manager))
@@ -179,7 +211,7 @@ func TestRuntimeConfigProviderCurrentReturnsMapClone(t *testing.T) {
179 provider := NewRuntimeConfigProvider(cfg, newMockConfigManager(t, &configManagerState{current: cfg}))211 provider := NewRuntimeConfigProvider(cfg, newMockConfigManager(t, &configManagerState{current: cfg}))
180 212
181 first := provider.Current()213 first := provider.Current()
182- first.UI.SearchShortcuts["gh"] = port.RuntimeSearchShortcut{URL: "mutated"}214+ first.UI.SearchShortcuts["gh"] = entity.RuntimeSearchShortcut{URL: "mutated"}
183 second := provider.Current()215 second := provider.Current()
184 216
185 if second.UI.SearchShortcuts["gh"].URL == "mutated" {217 if second.UI.SearchShortcuts["gh"].URL == "mutated" {
@@ -202,7 +234,7 @@ func TestRuntimeConfigProviderOnChangePassesNestedConfigClone(t *testing.T) {
202 manager := &configManagerState{}234 manager := &configManagerState{}
203 provider := NewRuntimeConfigProvider(config.DefaultConfig(), newMockConfigManager(t, manager))235 provider := NewRuntimeConfigProvider(config.DefaultConfig(), newMockConfigManager(t, manager))
204 236
205- provider.OnChange(func(snapshot port.RuntimeConfigSnapshot) {237+ provider.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
206 mutateNestedRuntimeConfigSnapshot(snapshot)238 mutateNestedRuntimeConfigSnapshot(snapshot)
207 })239 })
208 240
@@ -213,7 +245,7 @@ func TestRuntimeConfigProviderOnChangePassesNestedConfigClone(t *testing.T) {
213 245
214 func TestEngineSettingsPayloadFromNilConfigReturnsZeroPayload(t *testing.T) {246 func TestEngineSettingsPayloadFromNilConfigReturnsZeroPayload(t *testing.T) {
215 got := EngineSettingsPayloadFromConfig(nil)247 got := EngineSettingsPayloadFromConfig(nil)
216- if got != (port.EngineSettingsPayload{}) {248+ if got != (entity.EngineSettingsPayload{}) {
217 t.Fatalf("payload=%#v, want zero value", got)249 t.Fatalf("payload=%#v, want zero value", got)
218 }250 }
219 }251 }
@@ -241,7 +273,7 @@ func runtimeConfigWithNestedMutableFields() *config.Config {
241 return cfg273 return cfg
242 }274 }
243 275
244-func mutateNestedRuntimeConfigSnapshot(snapshot port.RuntimeConfigSnapshot) {276+func mutateNestedRuntimeConfigSnapshot(snapshot entity.RuntimeConfigSnapshot) {
245 mutateActionBinding(snapshot.UI.Workspace.PaneMode.Actions, "split-right", "mutated-pane")277 mutateActionBinding(snapshot.UI.Workspace.PaneMode.Actions, "split-right", "mutated-pane")
246 snapshot.UI.Workspace.PaneMode.Actions["added-pane"] = entity.ActionBinding{Keys: []string{"added"}}278 snapshot.UI.Workspace.PaneMode.Actions["added-pane"] = entity.ActionBinding{Keys: []string{"added"}}
247 279
@@ -269,7 +301,7 @@ func mutateActionBinding(actions map[string]entity.ActionBinding, action, key st
269 actions[action] = binding301 actions[action] = binding
270 }302 }
271 303
272-func assertNestedRuntimeConfigSnapshotUnchanged(t *testing.T, snapshot port.RuntimeConfigSnapshot) {304+func assertNestedRuntimeConfigSnapshotUnchanged(t *testing.T, snapshot entity.RuntimeConfigSnapshot) {
273 t.Helper()305 t.Helper()
274 306
275 assertActionBinding(t, snapshot.UI.Workspace.PaneMode.Actions, "split-right", "r")307 assertActionBinding(t, snapshot.UI.Workspace.PaneMode.Actions, "split-right", "r")
@@ -377,7 +409,7 @@ func TestRuntimeConfigSnapshotFromConfigMapsUIRuntimeFields(t *testing.T) {
377 if got.UI.SearchShortcuts["gh"].URL != "https://github.com/search?q=%s" {409 if got.UI.SearchShortcuts["gh"].URL != "https://github.com/search?q=%s" {
378 t.Fatalf("search shortcut not mapped: %#v", got.UI.SearchShortcuts)410 t.Fatalf("search shortcut not mapped: %#v", got.UI.SearchShortcuts)
379 }411 }
380- got.UI.SearchShortcuts["gh"] = port.RuntimeSearchShortcut{URL: "mutated"}412+ got.UI.SearchShortcuts["gh"] = entity.RuntimeSearchShortcut{URL: "mutated"}
381 if cfg.SearchShortcuts["gh"].URL == "mutated" {413 if cfg.SearchShortcuts["gh"].URL == "mutated" {
382 t.Fatal("snapshot must deep-copy search shortcut map")414 t.Fatal("snapshot must deep-copy search shortcut map")
383 }415 }
@@ -394,7 +426,7 @@ func TestRuntimeConfigSnapshotFromConfigDetachesNestedMutableFields(t *testing.T
394 426
395 func TestRuntimeConfigSnapshotFromNilConfigReturnsZeroSnapshot(t *testing.T) {427 func TestRuntimeConfigSnapshotFromNilConfigReturnsZeroSnapshot(t *testing.T) {
396 got := RuntimeConfigSnapshotFromConfig(nil)428 got := RuntimeConfigSnapshotFromConfig(nil)
397- if !reflect.DeepEqual(got, port.RuntimeConfigSnapshot{}) {429+ if !reflect.DeepEqual(got, entity.RuntimeConfigSnapshot{}) {
398 t.Fatalf("snapshot=%#v, want zero value", got)430 t.Fatalf("snapshot=%#v, want zero value", got)
399 }431 }
400 }432 }
@@ -403,32 +435,32 @@ func TestEngineSettingsPayloadFromConfigMapsHardwareDecodingModes(t *testing.T)
403 tests := []struct {435 tests := []struct {
404 name string436 name string
405 mode config.HardwareDecodingMode437 mode config.HardwareDecodingMode
406- want port.EngineHardwareDecodingMode438+ want entity.EngineHardwareDecodingMode
407 }{439 }{
408 {440 {
409 name: "auto",441 name: "auto",
410 mode: config.HardwareDecodingAuto,442 mode: config.HardwareDecodingAuto,
411- want: port.EngineHardwareDecodingAuto,443+ want: entity.EngineHardwareDecodingAuto,
412 },444 },
413 {445 {
414 name: "force",446 name: "force",
415 mode: config.HardwareDecodingForce,447 mode: config.HardwareDecodingForce,
416- want: port.EngineHardwareDecodingForce,448+ want: entity.EngineHardwareDecodingForce,
417 },449 },
418 {450 {
419 name: "disable",451 name: "disable",
420 mode: config.HardwareDecodingDisable,452 mode: config.HardwareDecodingDisable,
421- want: port.EngineHardwareDecodingDisable,453+ want: entity.EngineHardwareDecodingDisable,
422 },454 },
423 {455 {
424 name: "unknown",456 name: "unknown",
425 mode: config.HardwareDecodingMode("surprise"),457 mode: config.HardwareDecodingMode("surprise"),
426- want: port.EngineHardwareDecodingAuto,458+ want: entity.EngineHardwareDecodingAuto,
427 },459 },
428 {460 {
429 name: "zero value",461 name: "zero value",
430 mode: "",462 mode: "",
431- want: port.EngineHardwareDecodingAuto,463+ want: entity.EngineHardwareDecodingAuto,
432 },464 },
433 }465 }
434 466
R internal/application/port/engine_settings_test.go → internal/domain/entity/engine_settings_test.go +1 -1 renamed, 98% similar
@@ -1,4 +1,4 @@
1-package port
1+package entity
22
33 import (
44 "reflect"
@@ -1,4 +1,4 @@
1-package port1+package entity
2 2
3 import (3 import (
4 "reflect"4 "reflect"
A internal/domain/entity/runtime_config.go +80 -0
@@ -0,0 +1,80 @@
1+package entity
2+
3+// EngineHardwareDecodingMode controls engine-facing video hardware acceleration.
4+type EngineHardwareDecodingMode string
5+
6+const (
7+ EngineHardwareDecodingAuto EngineHardwareDecodingMode = "auto"
8+ EngineHardwareDecodingForce EngineHardwareDecodingMode = "force"
9+ EngineHardwareDecodingDisable EngineHardwareDecodingMode = "disable"
10+)
11+
12+// EngineWebContentSettingsPayload is the engine-facing runtime view of web
13+// content settings that can be applied to newly-created or existing webviews.
14+type EngineWebContentSettingsPayload struct {
15+ SansFont string
16+ SerifFont string
17+ MonospaceFont string
18+ DefaultFontSize int
19+ EnableDevTools bool
20+ CaptureConsole bool
21+ DrawCompositingIndicators bool
22+ HardwareDecoding EngineHardwareDecodingMode
23+ AutoCopyOnSelection bool
24+}
25+
26+// EngineSettingsPayload is the engine-facing boundary view of runtime config.
27+// Add fields here only when an engine needs to react to them at runtime.
28+type EngineSettingsPayload struct {
29+ DefaultUIScale float64
30+ WebContent EngineWebContentSettingsPayload
31+}
32+
33+// EngineSettingsUpdate carries a runtime config change to the engine.
34+type EngineSettingsUpdate struct {
35+ Settings EngineSettingsPayload
36+}
37+
38+type RuntimeConfigSnapshot struct {
39+ EngineSettings EngineSettingsPayload
40+ UI RuntimeUIConfig
41+}
42+
43+type RuntimeUIConfig struct {
44+ DefaultUIScale float64
45+ SidebarWidth int
46+ Appearance AppearanceConfig
47+ Workspace WorkspaceConfig
48+ Session SessionConfig
49+ Clipboard RuntimeClipboardConfig
50+ SearchShortcuts map[string]RuntimeSearchShortcut
51+ DefaultSearchEngine string
52+ Omnibox RuntimeOmniboxConfig
53+ Update RuntimeUpdateConfig
54+ Downloads RuntimeDownloadsConfig
55+}
56+
57+type RuntimeClipboardConfig struct {
58+ AutoCopyOnSelection bool
59+}
60+
61+type RuntimeSearchShortcut struct {
62+ URL string
63+ Description string
64+}
65+
66+type RuntimeOmniboxConfig struct {
67+ InitialBehavior OmniboxInitialBehavior
68+ MostVisitedDays int
69+ AutoOpenOnNewPane bool
70+}
71+
72+type RuntimeUpdateConfig struct {
73+ EnableOnStartup bool
74+ AutoDownload bool
75+ NotifyOnNewSettings bool
76+}
77+
78+type RuntimeDownloadsConfig struct {
79+ Path string
80+}
@@ -0,0 +1,80 @@
1+package entity
2+
3+// EngineHardwareDecodingMode controls engine-facing video hardware acceleration.
4+type EngineHardwareDecodingMode string
5+
6+const (
7+ EngineHardwareDecodingAuto EngineHardwareDecodingMode = "auto"
8+ EngineHardwareDecodingForce EngineHardwareDecodingMode = "force"
9+ EngineHardwareDecodingDisable EngineHardwareDecodingMode = "disable"
10+)
11+
12+// EngineWebContentSettingsPayload is the engine-facing runtime view of web
13+// content settings that can be applied to newly-created or existing webviews.
14+type EngineWebContentSettingsPayload struct {
15+ SansFont string
16+ SerifFont string
17+ MonospaceFont string
18+ DefaultFontSize int
19+ EnableDevTools bool
20+ CaptureConsole bool
21+ DrawCompositingIndicators bool
22+ HardwareDecoding EngineHardwareDecodingMode
23+ AutoCopyOnSelection bool
24+}
25+
26+// EngineSettingsPayload is the engine-facing boundary view of runtime config.
27+// Add fields here only when an engine needs to react to them at runtime.
28+type EngineSettingsPayload struct {
29+ DefaultUIScale float64
30+ WebContent EngineWebContentSettingsPayload
31+}
32+
33+// EngineSettingsUpdate carries a runtime config change to the engine.
34+type EngineSettingsUpdate struct {
35+ Settings EngineSettingsPayload
36+}
37+
38+type RuntimeConfigSnapshot struct {
39+ EngineSettings EngineSettingsPayload
40+ UI RuntimeUIConfig
41+}
42+
43+type RuntimeUIConfig struct {
44+ DefaultUIScale float64
45+ SidebarWidth int
46+ Appearance AppearanceConfig
47+ Workspace WorkspaceConfig
48+ Session SessionConfig
49+ Clipboard RuntimeClipboardConfig
50+ SearchShortcuts map[string]RuntimeSearchShortcut
51+ DefaultSearchEngine string
52+ Omnibox RuntimeOmniboxConfig
53+ Update RuntimeUpdateConfig
54+ Downloads RuntimeDownloadsConfig
55+}
56+
57+type RuntimeClipboardConfig struct {
58+ AutoCopyOnSelection bool
59+}
60+
61+type RuntimeSearchShortcut struct {
62+ URL string
63+ Description string
64+}
65+
66+type RuntimeOmniboxConfig struct {
67+ InitialBehavior OmniboxInitialBehavior
68+ MostVisitedDays int
69+ AutoOpenOnNewPane bool
70+}
71+
72+type RuntimeUpdateConfig struct {
73+ EnableOnStartup bool
74+ AutoDownload bool
75+ NotifyOnNewSettings bool
76+}
77+
78+type RuntimeDownloadsConfig struct {
79+ Path string
80+}
M internal/infrastructure/cef/engine.go +2 -1
@@ -15,6 +15,7 @@ import (
1515
1616 "github.com/bnema/dumber/internal/application/dto"
1717 "github.com/bnema/dumber/internal/application/port"
18+ "github.com/bnema/dumber/internal/domain/entity"
1819 "github.com/bnema/dumber/internal/logging"
1920 )
2021
@@ -355,7 +356,7 @@ func (e *Engine) UpdateAppearance(_ context.Context, r, g, b, alpha float64) err
355356 // existing views continue using their construction-time scale until reload under
356357 // a new engine lifetime. Browser zoom remains independently adjustable at
357358 // runtime through SetZoomLevel.
358-func (e *Engine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {
359+func (e *Engine) UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error {
359360 newScale := normalizedApplicationScale(update.Settings.DefaultUIScale)
360361 e.applicationScaleMu.Lock()
361362 oldScale := e.applicationScale
@@ -15,6 +15,7 @@ import (
15 15
16 "github.com/bnema/dumber/internal/application/dto"16 "github.com/bnema/dumber/internal/application/dto"
17 "github.com/bnema/dumber/internal/application/port"17 "github.com/bnema/dumber/internal/application/port"
18+ "github.com/bnema/dumber/internal/domain/entity"
18 "github.com/bnema/dumber/internal/logging"19 "github.com/bnema/dumber/internal/logging"
19 )20 )
20 21
@@ -355,7 +356,7 @@ func (e *Engine) UpdateAppearance(_ context.Context, r, g, b, alpha float64) err
355 // existing views continue using their construction-time scale until reload under356 // existing views continue using their construction-time scale until reload under
356 // a new engine lifetime. Browser zoom remains independently adjustable at357 // a new engine lifetime. Browser zoom remains independently adjustable at
357 // runtime through SetZoomLevel.358 // runtime through SetZoomLevel.
358-func (e *Engine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {359+func (e *Engine) UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error {
359 newScale := normalizedApplicationScale(update.Settings.DefaultUIScale)360 newScale := normalizedApplicationScale(update.Settings.DefaultUIScale)
360 e.applicationScaleMu.Lock()361 e.applicationScaleMu.Lock()
361 oldScale := e.applicationScale362 oldScale := e.applicationScale
M internal/infrastructure/cef/engine_settings_test.go +6 -6
@@ -5,14 +5,14 @@ import (
55 "sync"
66 "testing"
77
8- "github.com/bnema/dumber/internal/application/port"
8+ "github.com/bnema/dumber/internal/domain/entity"
99 )
1010
1111 func TestEngineUpdateSettingsUpdatesApplicationScaleFromBoundaryPayload(t *testing.T) {
1212 e := &Engine{applicationScale: 1}
1313
14- if err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{
15- Settings: port.EngineSettingsPayload{DefaultUIScale: 1.25},
14+ if err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{
15+ Settings: entity.EngineSettingsPayload{DefaultUIScale: 1.25},
1616 }); err != nil {
1717 t.Fatalf("UpdateSettings returned error: %v", err)
1818 }
@@ -24,7 +24,7 @@ func TestEngineUpdateSettingsUpdatesApplicationScaleFromBoundaryPayload(t *testi
2424 func TestEngineUpdateSettingsUsesZeroScaleWhenPayloadIsEmpty(t *testing.T) {
2525 e := &Engine{applicationScale: 1.25}
2626
27- if err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{}); err != nil {
27+ if err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{}); err != nil {
2828 t.Fatalf("UpdateSettings returned error: %v", err)
2929 }
3030 if got := e.currentApplicationScale(); got != 1 {
@@ -43,8 +43,8 @@ func TestEngineApplicationScaleConcurrentAccess(_ *testing.T) {
4343 }()
4444 go func(scale float64) {
4545 defer wg.Done()
46- _ = e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{
47- Settings: port.EngineSettingsPayload{DefaultUIScale: scale},
46+ _ = e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{
47+ Settings: entity.EngineSettingsPayload{DefaultUIScale: scale},
4848 })
4949 }(1 + float64(i)/10)
5050 }
@@ -5,14 +5,14 @@ import (
5 "sync"5 "sync"
6 "testing"6 "testing"
7 7
8- "github.com/bnema/dumber/internal/application/port"8+ "github.com/bnema/dumber/internal/domain/entity"
9 )9 )
10 10
11 func TestEngineUpdateSettingsUpdatesApplicationScaleFromBoundaryPayload(t *testing.T) {11 func TestEngineUpdateSettingsUpdatesApplicationScaleFromBoundaryPayload(t *testing.T) {
12 e := &Engine{applicationScale: 1}12 e := &Engine{applicationScale: 1}
13 13
14- if err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{14+ if err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{
15- Settings: port.EngineSettingsPayload{DefaultUIScale: 1.25},15+ Settings: entity.EngineSettingsPayload{DefaultUIScale: 1.25},
16 }); err != nil {16 }); err != nil {
17 t.Fatalf("UpdateSettings returned error: %v", err)17 t.Fatalf("UpdateSettings returned error: %v", err)
18 }18 }
@@ -24,7 +24,7 @@ func TestEngineUpdateSettingsUpdatesApplicationScaleFromBoundaryPayload(t *testi
24 func TestEngineUpdateSettingsUsesZeroScaleWhenPayloadIsEmpty(t *testing.T) {24 func TestEngineUpdateSettingsUsesZeroScaleWhenPayloadIsEmpty(t *testing.T) {
25 e := &Engine{applicationScale: 1.25}25 e := &Engine{applicationScale: 1.25}
26 26
27- if err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{}); err != nil {27+ if err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{}); err != nil {
28 t.Fatalf("UpdateSettings returned error: %v", err)28 t.Fatalf("UpdateSettings returned error: %v", err)
29 }29 }
30 if got := e.currentApplicationScale(); got != 1 {30 if got := e.currentApplicationScale(); got != 1 {
@@ -43,8 +43,8 @@ func TestEngineApplicationScaleConcurrentAccess(_ *testing.T) {
43 }()43 }()
44 go func(scale float64) {44 go func(scale float64) {
45 defer wg.Done()45 defer wg.Done()
46- _ = e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{46+ _ = e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{
47- Settings: port.EngineSettingsPayload{DefaultUIScale: scale},47+ Settings: entity.EngineSettingsPayload{DefaultUIScale: scale},
48 })48 })
49 }(1 + float64(i)/10)49 }(1 + float64(i)/10)
50 }50 }
M internal/infrastructure/webkit/engine.go +2 -1
@@ -5,6 +5,7 @@ import (
55 "fmt"
66
77 "github.com/bnema/dumber/internal/application/port"
8+ "github.com/bnema/dumber/internal/domain/entity"
89 "github.com/bnema/dumber/internal/infrastructure/filtering"
910 "github.com/bnema/dumber/internal/infrastructure/handlers"
1011 "github.com/rs/zerolog"
@@ -155,7 +156,7 @@ func (e *Engine) UpdateAppearance(_ context.Context, r, g, b, alpha float64) err
155156 }
156157
157158 // UpdateSettings applies runtime config changes to engine settings.
158-func (e *Engine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {
159+func (e *Engine) UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error {
159160 if e.settings != nil {
160161 e.settings.UpdateFromPayload(ctx, update.Settings)
161162 }
@@ -5,6 +5,7 @@ import (
5 "fmt"5 "fmt"
6 6
7 "github.com/bnema/dumber/internal/application/port"7 "github.com/bnema/dumber/internal/application/port"
8+ "github.com/bnema/dumber/internal/domain/entity"
8 "github.com/bnema/dumber/internal/infrastructure/filtering"9 "github.com/bnema/dumber/internal/infrastructure/filtering"
9 "github.com/bnema/dumber/internal/infrastructure/handlers"10 "github.com/bnema/dumber/internal/infrastructure/handlers"
10 "github.com/rs/zerolog"11 "github.com/rs/zerolog"
@@ -155,7 +156,7 @@ func (e *Engine) UpdateAppearance(_ context.Context, r, g, b, alpha float64) err
155 }156 }
156 157
157 // UpdateSettings applies runtime config changes to engine settings.158 // UpdateSettings applies runtime config changes to engine settings.
158-func (e *Engine) UpdateSettings(ctx context.Context, update port.EngineSettingsUpdate) error {159+func (e *Engine) UpdateSettings(ctx context.Context, update entity.EngineSettingsUpdate) error {
159 if e.settings != nil {160 if e.settings != nil {
160 e.settings.UpdateFromPayload(ctx, update.Settings)161 e.settings.UpdateFromPayload(ctx, update.Settings)
161 }162 }
M internal/infrastructure/webkit/engine_init.go +2 -1
@@ -7,6 +7,7 @@ import (
77 "github.com/bnema/dumber/assets"
88 "github.com/bnema/dumber/internal/application/port"
99 "github.com/bnema/dumber/internal/application/usecase"
10+ "github.com/bnema/dumber/internal/domain/entity"
1011 "github.com/bnema/dumber/internal/infrastructure/config"
1112 "github.com/bnema/dumber/internal/infrastructure/env"
1213 "github.com/bnema/dumber/internal/infrastructure/filtering"
@@ -25,7 +26,7 @@ func NewEngine(
2526 opts port.EngineOptions,
2627 profile runtimeprofile.Profile,
2728 wkCfg WebKitEngineConfig,
28- initialSettings port.EngineSettingsPayload,
29+ initialSettings entity.EngineSettingsPayload,
2930 currentConfigPayload func() ([]byte, error),
3031 defaultConfigPayload func() ([]byte, error),
3132 themeManager *theme.Manager,
@@ -7,6 +7,7 @@ import (
7 "github.com/bnema/dumber/assets"7 "github.com/bnema/dumber/assets"
8 "github.com/bnema/dumber/internal/application/port"8 "github.com/bnema/dumber/internal/application/port"
9 "github.com/bnema/dumber/internal/application/usecase"9 "github.com/bnema/dumber/internal/application/usecase"
10+ "github.com/bnema/dumber/internal/domain/entity"
10 "github.com/bnema/dumber/internal/infrastructure/config"11 "github.com/bnema/dumber/internal/infrastructure/config"
11 "github.com/bnema/dumber/internal/infrastructure/env"12 "github.com/bnema/dumber/internal/infrastructure/env"
12 "github.com/bnema/dumber/internal/infrastructure/filtering"13 "github.com/bnema/dumber/internal/infrastructure/filtering"
@@ -25,7 +26,7 @@ func NewEngine(
25 opts port.EngineOptions,26 opts port.EngineOptions,
26 profile runtimeprofile.Profile,27 profile runtimeprofile.Profile,
27 wkCfg WebKitEngineConfig,28 wkCfg WebKitEngineConfig,
28- initialSettings port.EngineSettingsPayload,29+ initialSettings entity.EngineSettingsPayload,
29 currentConfigPayload func() ([]byte, error),30 currentConfigPayload func() ([]byte, error),
30 defaultConfigPayload func() ([]byte, error),31 defaultConfigPayload func() ([]byte, error),
31 themeManager *theme.Manager,32 themeManager *theme.Manager,
M internal/infrastructure/webkit/engine_runtime_test.go +11 -10
@@ -5,21 +5,22 @@ import (
55 "testing"
66
77 "github.com/bnema/dumber/internal/application/port"
8+ "github.com/bnema/dumber/internal/domain/entity"
89 "github.com/stretchr/testify/require"
910 )
1011
1112 func TestEngine_UpdateSettings_AcceptsTypedSettingsPayload(t *testing.T) {
12- e := &Engine{settings: NewSettingsManager(context.Background(), port.EngineSettingsPayload{})}
13+ e := &Engine{settings: NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})}
1314
14- err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{
15- Settings: port.EngineSettingsPayload{
15+ err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{
16+ Settings: entity.EngineSettingsPayload{
1617 DefaultUIScale: 1.25,
17- WebContent: port.EngineWebContentSettingsPayload{
18+ WebContent: entity.EngineWebContentSettingsPayload{
1819 SansFont: "Inter",
1920 EnableDevTools: true,
2021 CaptureConsole: true,
2122 DrawCompositingIndicators: true,
22- HardwareDecoding: port.EngineHardwareDecodingDisable,
23+ HardwareDecoding: entity.EngineHardwareDecodingDisable,
2324 },
2425 },
2526 })
@@ -28,13 +29,13 @@ func TestEngine_UpdateSettings_AcceptsTypedSettingsPayload(t *testing.T) {
2829 require.True(t, e.settings.current().WebContent.EnableDevTools)
2930 require.True(t, e.settings.current().WebContent.CaptureConsole)
3031 require.True(t, e.settings.current().WebContent.DrawCompositingIndicators)
31- require.Equal(t, port.EngineHardwareDecodingDisable, e.settings.current().WebContent.HardwareDecoding)
32+ require.Equal(t, entity.EngineHardwareDecodingDisable, e.settings.current().WebContent.HardwareDecoding)
3233 }
3334
3435 func TestEngine_UpdateSettings_NilSettings(t *testing.T) {
3536 // settings is nil — should not panic, just be a no-op.
3637 e := &Engine{}
37- err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{})
38+ err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{})
3839 require.NoError(t, err)
3940 }
4041
@@ -74,7 +75,7 @@ func TestEngine_Close_NilPool(t *testing.T) {
7475 }
7576
7677 func TestEngineConfigureContentInjectorAutoCopyGetterReadsCurrentPayload(t *testing.T) {
77- settings := NewSettingsManager(context.Background(), port.EngineSettingsPayload{})
78+ settings := NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})
7879 injector := NewContentInjector(nil)
7980
8081 engineConfigureContentInjectorRuntimeSettings(injector, settings)
@@ -82,8 +83,8 @@ func TestEngineConfigureContentInjectorAutoCopyGetterReadsCurrentPayload(t *test
8283 require.NotNil(t, injector.autoCopyConfigGetter)
8384 require.False(t, injector.autoCopyConfigGetter())
8485
85- settings.UpdateFromPayload(context.Background(), port.EngineSettingsPayload{
86- WebContent: port.EngineWebContentSettingsPayload{
86+ settings.UpdateFromPayload(context.Background(), entity.EngineSettingsPayload{
87+ WebContent: entity.EngineWebContentSettingsPayload{
8788 AutoCopyOnSelection: true,
8889 },
8990 })
@@ -5,21 +5,22 @@ import (
5 "testing"5 "testing"
6 6
7 "github.com/bnema/dumber/internal/application/port"7 "github.com/bnema/dumber/internal/application/port"
8+ "github.com/bnema/dumber/internal/domain/entity"
8 "github.com/stretchr/testify/require"9 "github.com/stretchr/testify/require"
9 )10 )
10 11
11 func TestEngine_UpdateSettings_AcceptsTypedSettingsPayload(t *testing.T) {12 func TestEngine_UpdateSettings_AcceptsTypedSettingsPayload(t *testing.T) {
12- e := &Engine{settings: NewSettingsManager(context.Background(), port.EngineSettingsPayload{})}13+ e := &Engine{settings: NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})}
13 14
14- err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{15+ err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{
15- Settings: port.EngineSettingsPayload{16+ Settings: entity.EngineSettingsPayload{
16 DefaultUIScale: 1.25,17 DefaultUIScale: 1.25,
17- WebContent: port.EngineWebContentSettingsPayload{18+ WebContent: entity.EngineWebContentSettingsPayload{
18 SansFont: "Inter",19 SansFont: "Inter",
19 EnableDevTools: true,20 EnableDevTools: true,
20 CaptureConsole: true,21 CaptureConsole: true,
21 DrawCompositingIndicators: true,22 DrawCompositingIndicators: true,
22- HardwareDecoding: port.EngineHardwareDecodingDisable,23+ HardwareDecoding: entity.EngineHardwareDecodingDisable,
23 },24 },
24 },25 },
25 })26 })
@@ -28,13 +29,13 @@ func TestEngine_UpdateSettings_AcceptsTypedSettingsPayload(t *testing.T) {
28 require.True(t, e.settings.current().WebContent.EnableDevTools)29 require.True(t, e.settings.current().WebContent.EnableDevTools)
29 require.True(t, e.settings.current().WebContent.CaptureConsole)30 require.True(t, e.settings.current().WebContent.CaptureConsole)
30 require.True(t, e.settings.current().WebContent.DrawCompositingIndicators)31 require.True(t, e.settings.current().WebContent.DrawCompositingIndicators)
31- require.Equal(t, port.EngineHardwareDecodingDisable, e.settings.current().WebContent.HardwareDecoding)32+ require.Equal(t, entity.EngineHardwareDecodingDisable, e.settings.current().WebContent.HardwareDecoding)
32 }33 }
33 34
34 func TestEngine_UpdateSettings_NilSettings(t *testing.T) {35 func TestEngine_UpdateSettings_NilSettings(t *testing.T) {
35 // settings is nil — should not panic, just be a no-op.36 // settings is nil — should not panic, just be a no-op.
36 e := &Engine{}37 e := &Engine{}
37- err := e.UpdateSettings(context.Background(), port.EngineSettingsUpdate{})38+ err := e.UpdateSettings(context.Background(), entity.EngineSettingsUpdate{})
38 require.NoError(t, err)39 require.NoError(t, err)
39 }40 }
40 41
@@ -74,7 +75,7 @@ func TestEngine_Close_NilPool(t *testing.T) {
74 }75 }
75 76
76 func TestEngineConfigureContentInjectorAutoCopyGetterReadsCurrentPayload(t *testing.T) {77 func TestEngineConfigureContentInjectorAutoCopyGetterReadsCurrentPayload(t *testing.T) {
77- settings := NewSettingsManager(context.Background(), port.EngineSettingsPayload{})78+ settings := NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})
78 injector := NewContentInjector(nil)79 injector := NewContentInjector(nil)
79 80
80 engineConfigureContentInjectorRuntimeSettings(injector, settings)81 engineConfigureContentInjectorRuntimeSettings(injector, settings)
@@ -82,8 +83,8 @@ func TestEngineConfigureContentInjectorAutoCopyGetterReadsCurrentPayload(t *test
82 require.NotNil(t, injector.autoCopyConfigGetter)83 require.NotNil(t, injector.autoCopyConfigGetter)
83 require.False(t, injector.autoCopyConfigGetter())84 require.False(t, injector.autoCopyConfigGetter())
84 85
85- settings.UpdateFromPayload(context.Background(), port.EngineSettingsPayload{86+ settings.UpdateFromPayload(context.Background(), entity.EngineSettingsPayload{
86- WebContent: port.EngineWebContentSettingsPayload{87+ WebContent: entity.EngineWebContentSettingsPayload{
87 AutoCopyOnSelection: true,88 AutoCopyOnSelection: true,
88 },89 },
89 })90 })
M internal/infrastructure/webkit/pool_context_menu_test.go +2 -2
@@ -4,7 +4,7 @@ import (
44 "context"
55 "testing"
66
7- "github.com/bnema/dumber/internal/application/port"
7+ "github.com/bnema/dumber/internal/domain/entity"
88 "github.com/bnema/puregotk/v4/webkit"
99 )
1010
@@ -32,7 +32,7 @@ func TestNeedsExplicitContextMenuSignalOnAcquire(t *testing.T) {
3232 }
3333
3434 func TestShouldReapplySettingsOnAcquire(t *testing.T) {
35- settings := NewSettingsManager(context.Background(), port.EngineSettingsPayload{})
35+ settings := NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})
3636
3737 tests := []struct {
3838 name string
@@ -4,7 +4,7 @@ import (
4 "context"4 "context"
5 "testing"5 "testing"
6 6
7- "github.com/bnema/dumber/internal/application/port"7+ "github.com/bnema/dumber/internal/domain/entity"
8 "github.com/bnema/puregotk/v4/webkit"8 "github.com/bnema/puregotk/v4/webkit"
9 )9 )
10 10
@@ -32,7 +32,7 @@ func TestNeedsExplicitContextMenuSignalOnAcquire(t *testing.T) {
32 }32 }
33 33
34 func TestShouldReapplySettingsOnAcquire(t *testing.T) {34 func TestShouldReapplySettingsOnAcquire(t *testing.T) {
35- settings := NewSettingsManager(context.Background(), port.EngineSettingsPayload{})35+ settings := NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})
36 36
37 tests := []struct {37 tests := []struct {
38 name string38 name string
M internal/infrastructure/webkit/settings.go +11 -11
@@ -4,7 +4,7 @@ import (
44 "context"
55 "sync"
66
7- "github.com/bnema/dumber/internal/application/port"
7+ "github.com/bnema/dumber/internal/domain/entity"
88 "github.com/bnema/dumber/internal/logging"
99 "github.com/bnema/puregotk/v4/webkit"
1010 "github.com/rs/zerolog"
@@ -27,18 +27,18 @@ type mediaSettings interface {
2727
2828 // SettingsManager creates and manages WebKit Settings instances from payloads.
2929 type SettingsManager struct {
30- settings port.EngineSettingsPayload
30+ settings entity.EngineSettingsPayload
3131 mu sync.RWMutex
3232 }
3333
3434 // NewSettingsManager creates a new SettingsManager with the given payload.
35-func NewSettingsManager(ctx context.Context, settings port.EngineSettingsPayload) *SettingsManager {
35+func NewSettingsManager(ctx context.Context, settings entity.EngineSettingsPayload) *SettingsManager {
3636 log := logging.FromContext(ctx)
3737 log.Debug().Msg("creating settings manager")
3838 return &SettingsManager{settings: settings}
3939 }
4040
41-func (sm *SettingsManager) current() port.EngineSettingsPayload {
41+func (sm *SettingsManager) current() entity.EngineSettingsPayload {
4242 sm.mu.RLock()
4343 defer sm.mu.RUnlock()
4444 return sm.settings
@@ -60,7 +60,7 @@ func (sm *SettingsManager) CreateSettings(ctx context.Context) *webkit.Settings
6060 }
6161
6262 // applySettings applies settings payload to a webkit.Settings instance.
63-func (sm *SettingsManager) applySettings(ctx context.Context, settings *webkit.Settings, payload port.EngineSettingsPayload) {
63+func (sm *SettingsManager) applySettings(ctx context.Context, settings *webkit.Settings, payload entity.EngineSettingsPayload) {
6464 if sm == nil {
6565 return
6666 }
@@ -91,7 +91,7 @@ func applyJavaScriptSettings(settings *webkit.Settings) {
9191 settings.SetEnableJavascriptMarkup(true)
9292 }
9393
94-func applyFontSettings(settings *webkit.Settings, payload port.EngineWebContentSettingsPayload) {
94+func applyFontSettings(settings *webkit.Settings, payload entity.EngineWebContentSettingsPayload) {
9595 if payload.SansFont != "" {
9696 settings.SetDefaultFontFamily(payload.SansFont)
9797 settings.SetSansSerifFontFamily(payload.SansFont)
@@ -107,7 +107,7 @@ func applyFontSettings(settings *webkit.Settings, payload port.EngineWebContentS
107107 }
108108 }
109109
110-func applyDebugSettings(settings *webkit.Settings, payload port.EngineWebContentSettingsPayload) {
110+func applyDebugSettings(settings *webkit.Settings, payload entity.EngineWebContentSettingsPayload) {
111111 settings.SetEnableDeveloperExtras(payload.EnableDevTools)
112112 settings.SetEnableWriteConsoleMessagesToStdout(payload.CaptureConsole)
113113 settings.SetDrawCompositingIndicators(payload.DrawCompositingIndicators)
@@ -119,7 +119,7 @@ func applyBrowsingSettings(settings *webkit.Settings) {
119119 settings.SetEnableSiteSpecificQuirks(true)
120120 }
121121
122-func applyMediaSettings(settings mediaSettings, mode port.EngineHardwareDecodingMode, log *zerolog.Logger) {
122+func applyMediaSettings(settings mediaSettings, mode entity.EngineHardwareDecodingMode, log *zerolog.Logger) {
123123 settings.SetEnableWebaudio(true)
124124 settings.SetEnableWebgl(true)
125125 settings.SetEnableMedia(true)
@@ -130,12 +130,12 @@ func applyMediaSettings(settings mediaSettings, mode port.EngineHardwareDecoding
130130 settings.SetMediaPlaybackAllowsInline(true)
131131
132132 switch mode {
133- case port.EngineHardwareDecodingForce:
133+ case entity.EngineHardwareDecodingForce:
134134 hwTypes := hardwareRequiredContentTypes
135135 settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyAlwaysValue)
136136 settings.SetMediaContentTypesRequiringHardwareSupport(&hwTypes)
137137 log.Debug().Msg("hardware decoding: forced (may fail without hw support)")
138- case port.EngineHardwareDecodingDisable:
138+ case entity.EngineHardwareDecodingDisable:
139139 emptyTypes := ""
140140 settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyNeverValue)
141141 settings.SetMediaContentTypesRequiringHardwareSupport(&emptyTypes)
@@ -174,7 +174,7 @@ func applyWebRTCSettings(settings *webkit.Settings) {
174174 // UpdateFromPayload updates the manager with a new payload (for hot-reload).
175175 // Note: This doesn't update already-created Settings instances.
176176 // New WebViews will use the updated payload.
177-func (sm *SettingsManager) UpdateFromPayload(ctx context.Context, settings port.EngineSettingsPayload) {
177+func (sm *SettingsManager) UpdateFromPayload(ctx context.Context, settings entity.EngineSettingsPayload) {
178178 log := logging.FromContext(ctx)
179179 sm.mu.Lock()
180180 defer sm.mu.Unlock()
@@ -4,7 +4,7 @@ import (
4 "context"4 "context"
5 "sync"5 "sync"
6 6
7- "github.com/bnema/dumber/internal/application/port"7+ "github.com/bnema/dumber/internal/domain/entity"
8 "github.com/bnema/dumber/internal/logging"8 "github.com/bnema/dumber/internal/logging"
9 "github.com/bnema/puregotk/v4/webkit"9 "github.com/bnema/puregotk/v4/webkit"
10 "github.com/rs/zerolog"10 "github.com/rs/zerolog"
@@ -27,18 +27,18 @@ type mediaSettings interface {
27 27
28 // SettingsManager creates and manages WebKit Settings instances from payloads.28 // SettingsManager creates and manages WebKit Settings instances from payloads.
29 type SettingsManager struct {29 type SettingsManager struct {
30- settings port.EngineSettingsPayload30+ settings entity.EngineSettingsPayload
31 mu sync.RWMutex31 mu sync.RWMutex
32 }32 }
33 33
34 // NewSettingsManager creates a new SettingsManager with the given payload.34 // NewSettingsManager creates a new SettingsManager with the given payload.
35-func NewSettingsManager(ctx context.Context, settings port.EngineSettingsPayload) *SettingsManager {35+func NewSettingsManager(ctx context.Context, settings entity.EngineSettingsPayload) *SettingsManager {
36 log := logging.FromContext(ctx)36 log := logging.FromContext(ctx)
37 log.Debug().Msg("creating settings manager")37 log.Debug().Msg("creating settings manager")
38 return &SettingsManager{settings: settings}38 return &SettingsManager{settings: settings}
39 }39 }
40 40
41-func (sm *SettingsManager) current() port.EngineSettingsPayload {41+func (sm *SettingsManager) current() entity.EngineSettingsPayload {
42 sm.mu.RLock()42 sm.mu.RLock()
43 defer sm.mu.RUnlock()43 defer sm.mu.RUnlock()
44 return sm.settings44 return sm.settings
@@ -60,7 +60,7 @@ func (sm *SettingsManager) CreateSettings(ctx context.Context) *webkit.Settings
60 }60 }
61 61
62 // applySettings applies settings payload to a webkit.Settings instance.62 // applySettings applies settings payload to a webkit.Settings instance.
63-func (sm *SettingsManager) applySettings(ctx context.Context, settings *webkit.Settings, payload port.EngineSettingsPayload) {63+func (sm *SettingsManager) applySettings(ctx context.Context, settings *webkit.Settings, payload entity.EngineSettingsPayload) {
64 if sm == nil {64 if sm == nil {
65 return65 return
66 }66 }
@@ -91,7 +91,7 @@ func applyJavaScriptSettings(settings *webkit.Settings) {
91 settings.SetEnableJavascriptMarkup(true)91 settings.SetEnableJavascriptMarkup(true)
92 }92 }
93 93
94-func applyFontSettings(settings *webkit.Settings, payload port.EngineWebContentSettingsPayload) {94+func applyFontSettings(settings *webkit.Settings, payload entity.EngineWebContentSettingsPayload) {
95 if payload.SansFont != "" {95 if payload.SansFont != "" {
96 settings.SetDefaultFontFamily(payload.SansFont)96 settings.SetDefaultFontFamily(payload.SansFont)
97 settings.SetSansSerifFontFamily(payload.SansFont)97 settings.SetSansSerifFontFamily(payload.SansFont)
@@ -107,7 +107,7 @@ func applyFontSettings(settings *webkit.Settings, payload port.EngineWebContentS
107 }107 }
108 }108 }
109 109
110-func applyDebugSettings(settings *webkit.Settings, payload port.EngineWebContentSettingsPayload) {110+func applyDebugSettings(settings *webkit.Settings, payload entity.EngineWebContentSettingsPayload) {
111 settings.SetEnableDeveloperExtras(payload.EnableDevTools)111 settings.SetEnableDeveloperExtras(payload.EnableDevTools)
112 settings.SetEnableWriteConsoleMessagesToStdout(payload.CaptureConsole)112 settings.SetEnableWriteConsoleMessagesToStdout(payload.CaptureConsole)
113 settings.SetDrawCompositingIndicators(payload.DrawCompositingIndicators)113 settings.SetDrawCompositingIndicators(payload.DrawCompositingIndicators)
@@ -119,7 +119,7 @@ func applyBrowsingSettings(settings *webkit.Settings) {
119 settings.SetEnableSiteSpecificQuirks(true)119 settings.SetEnableSiteSpecificQuirks(true)
120 }120 }
121 121
122-func applyMediaSettings(settings mediaSettings, mode port.EngineHardwareDecodingMode, log *zerolog.Logger) {122+func applyMediaSettings(settings mediaSettings, mode entity.EngineHardwareDecodingMode, log *zerolog.Logger) {
123 settings.SetEnableWebaudio(true)123 settings.SetEnableWebaudio(true)
124 settings.SetEnableWebgl(true)124 settings.SetEnableWebgl(true)
125 settings.SetEnableMedia(true)125 settings.SetEnableMedia(true)
@@ -130,12 +130,12 @@ func applyMediaSettings(settings mediaSettings, mode port.EngineHardwareDecoding
130 settings.SetMediaPlaybackAllowsInline(true)130 settings.SetMediaPlaybackAllowsInline(true)
131 131
132 switch mode {132 switch mode {
133- case port.EngineHardwareDecodingForce:133+ case entity.EngineHardwareDecodingForce:
134 hwTypes := hardwareRequiredContentTypes134 hwTypes := hardwareRequiredContentTypes
135 settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyAlwaysValue)135 settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyAlwaysValue)
136 settings.SetMediaContentTypesRequiringHardwareSupport(&hwTypes)136 settings.SetMediaContentTypesRequiringHardwareSupport(&hwTypes)
137 log.Debug().Msg("hardware decoding: forced (may fail without hw support)")137 log.Debug().Msg("hardware decoding: forced (may fail without hw support)")
138- case port.EngineHardwareDecodingDisable:138+ case entity.EngineHardwareDecodingDisable:
139 emptyTypes := ""139 emptyTypes := ""
140 settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyNeverValue)140 settings.SetHardwareAccelerationPolicy(webkit.HardwareAccelerationPolicyNeverValue)
141 settings.SetMediaContentTypesRequiringHardwareSupport(&emptyTypes)141 settings.SetMediaContentTypesRequiringHardwareSupport(&emptyTypes)
@@ -174,7 +174,7 @@ func applyWebRTCSettings(settings *webkit.Settings) {
174 // UpdateFromPayload updates the manager with a new payload (for hot-reload).174 // UpdateFromPayload updates the manager with a new payload (for hot-reload).
175 // Note: This doesn't update already-created Settings instances.175 // Note: This doesn't update already-created Settings instances.
176 // New WebViews will use the updated payload.176 // New WebViews will use the updated payload.
177-func (sm *SettingsManager) UpdateFromPayload(ctx context.Context, settings port.EngineSettingsPayload) {177+func (sm *SettingsManager) UpdateFromPayload(ctx context.Context, settings entity.EngineSettingsPayload) {
178 log := logging.FromContext(ctx)178 log := logging.FromContext(ctx)
179 sm.mu.Lock()179 sm.mu.Lock()
180 defer sm.mu.Unlock()180 defer sm.mu.Unlock()
M internal/infrastructure/webkit/settings_runtime_test.go +14 -14
@@ -4,20 +4,20 @@ import (
44 "context"
55 "testing"
66
7- "github.com/bnema/dumber/internal/application/port"
7+ "github.com/bnema/dumber/internal/domain/entity"
88 "github.com/bnema/puregotk/v4/webkit"
99 "github.com/rs/zerolog"
1010 )
1111
1212 func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T) {
13- sm := NewSettingsManager(context.Background(), port.EngineSettingsPayload{})
14- payload := port.EngineSettingsPayload{
15- WebContent: port.EngineWebContentSettingsPayload{
13+ sm := NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})
14+ payload := entity.EngineSettingsPayload{
15+ WebContent: entity.EngineWebContentSettingsPayload{
1616 SansFont: "Inter",
1717 SerifFont: "Literata",
1818 MonospaceFont: "Fira Code",
1919 DefaultFontSize: 16,
20- HardwareDecoding: port.EngineHardwareDecodingForce,
20+ HardwareDecoding: entity.EngineHardwareDecodingForce,
2121 },
2222 }
2323
@@ -28,7 +28,7 @@ func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T
2828 got.WebContent.SerifFont != "Literata" ||
2929 got.WebContent.MonospaceFont != "Fira Code" ||
3030 got.WebContent.DefaultFontSize != 16 ||
31- got.WebContent.HardwareDecoding != port.EngineHardwareDecodingForce {
31+ got.WebContent.HardwareDecoding != entity.EngineHardwareDecodingForce {
3232 t.Fatalf("stored payload=%#v", got)
3333 }
3434 }
@@ -36,30 +36,30 @@ func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T
3636 func TestApplyMediaSettingsUpdatesHardwareDecodingKnobsOnSameSettingsObject(t *testing.T) {
3737 tests := []struct {
3838 name string
39- first port.EngineHardwareDecodingMode
40- next port.EngineHardwareDecodingMode
39+ first entity.EngineHardwareDecodingMode
40+ next entity.EngineHardwareDecodingMode
4141 wantPolicy webkit.HardwareAccelerationPolicy
4242 wantHWTypes string
4343 wantEmptyHWT bool
4444 }{
4545 {
4646 name: "disable to force resets acceleration policy",
47- first: port.EngineHardwareDecodingDisable,
48- next: port.EngineHardwareDecodingForce,
47+ first: entity.EngineHardwareDecodingDisable,
48+ next: entity.EngineHardwareDecodingForce,
4949 wantPolicy: webkit.HardwareAccelerationPolicyAlwaysValue,
5050 wantHWTypes: "video/av01;video/mp4;video/webm;video/x-h264;video/x-h265",
5151 },
5252 {
5353 name: "force to disable clears required content types",
54- first: port.EngineHardwareDecodingForce,
55- next: port.EngineHardwareDecodingDisable,
54+ first: entity.EngineHardwareDecodingForce,
55+ next: entity.EngineHardwareDecodingDisable,
5656 wantPolicy: webkit.HardwareAccelerationPolicyNeverValue,
5757 wantEmptyHWT: true,
5858 },
5959 {
6060 name: "disable to auto resets acceleration policy",
61- first: port.EngineHardwareDecodingDisable,
62- next: port.EngineHardwareDecodingAuto,
61+ first: entity.EngineHardwareDecodingDisable,
62+ next: entity.EngineHardwareDecodingAuto,
6363 wantPolicy: webkit.HardwareAccelerationPolicyAlwaysValue,
6464 wantEmptyHWT: true,
6565 },
@@ -4,20 +4,20 @@ import (
4 "context"4 "context"
5 "testing"5 "testing"
6 6
7- "github.com/bnema/dumber/internal/application/port"7+ "github.com/bnema/dumber/internal/domain/entity"
8 "github.com/bnema/puregotk/v4/webkit"8 "github.com/bnema/puregotk/v4/webkit"
9 "github.com/rs/zerolog"9 "github.com/rs/zerolog"
10 )10 )
11 11
12 func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T) {12 func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T) {
13- sm := NewSettingsManager(context.Background(), port.EngineSettingsPayload{})13+ sm := NewSettingsManager(context.Background(), entity.EngineSettingsPayload{})
14- payload := port.EngineSettingsPayload{14+ payload := entity.EngineSettingsPayload{
15- WebContent: port.EngineWebContentSettingsPayload{15+ WebContent: entity.EngineWebContentSettingsPayload{
16 SansFont: "Inter",16 SansFont: "Inter",
17 SerifFont: "Literata",17 SerifFont: "Literata",
18 MonospaceFont: "Fira Code",18 MonospaceFont: "Fira Code",
19 DefaultFontSize: 16,19 DefaultFontSize: 16,
20- HardwareDecoding: port.EngineHardwareDecodingForce,20+ HardwareDecoding: entity.EngineHardwareDecodingForce,
21 },21 },
22 }22 }
23 23
@@ -28,7 +28,7 @@ func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T
28 got.WebContent.SerifFont != "Literata" ||28 got.WebContent.SerifFont != "Literata" ||
29 got.WebContent.MonospaceFont != "Fira Code" ||29 got.WebContent.MonospaceFont != "Fira Code" ||
30 got.WebContent.DefaultFontSize != 16 ||30 got.WebContent.DefaultFontSize != 16 ||
31- got.WebContent.HardwareDecoding != port.EngineHardwareDecodingForce {31+ got.WebContent.HardwareDecoding != entity.EngineHardwareDecodingForce {
32 t.Fatalf("stored payload=%#v", got)32 t.Fatalf("stored payload=%#v", got)
33 }33 }
34 }34 }
@@ -36,30 +36,30 @@ func TestSettingsManagerUpdateFromPayloadStoresTypedRuntimeSettings(t *testing.T
36 func TestApplyMediaSettingsUpdatesHardwareDecodingKnobsOnSameSettingsObject(t *testing.T) {36 func TestApplyMediaSettingsUpdatesHardwareDecodingKnobsOnSameSettingsObject(t *testing.T) {
37 tests := []struct {37 tests := []struct {
38 name string38 name string
39- first port.EngineHardwareDecodingMode39+ first entity.EngineHardwareDecodingMode
40- next port.EngineHardwareDecodingMode40+ next entity.EngineHardwareDecodingMode
41 wantPolicy webkit.HardwareAccelerationPolicy41 wantPolicy webkit.HardwareAccelerationPolicy
42 wantHWTypes string42 wantHWTypes string
43 wantEmptyHWT bool43 wantEmptyHWT bool
44 }{44 }{
45 {45 {
46 name: "disable to force resets acceleration policy",46 name: "disable to force resets acceleration policy",
47- first: port.EngineHardwareDecodingDisable,47+ first: entity.EngineHardwareDecodingDisable,
48- next: port.EngineHardwareDecodingForce,48+ next: entity.EngineHardwareDecodingForce,
49 wantPolicy: webkit.HardwareAccelerationPolicyAlwaysValue,49 wantPolicy: webkit.HardwareAccelerationPolicyAlwaysValue,
50 wantHWTypes: "video/av01;video/mp4;video/webm;video/x-h264;video/x-h265",50 wantHWTypes: "video/av01;video/mp4;video/webm;video/x-h264;video/x-h265",
51 },51 },
52 {52 {
53 name: "force to disable clears required content types",53 name: "force to disable clears required content types",
54- first: port.EngineHardwareDecodingForce,54+ first: entity.EngineHardwareDecodingForce,
55- next: port.EngineHardwareDecodingDisable,55+ next: entity.EngineHardwareDecodingDisable,
56 wantPolicy: webkit.HardwareAccelerationPolicyNeverValue,56 wantPolicy: webkit.HardwareAccelerationPolicyNeverValue,
57 wantEmptyHWT: true,57 wantEmptyHWT: true,
58 },58 },
59 {59 {
60 name: "disable to auto resets acceleration policy",60 name: "disable to auto resets acceleration policy",
61- first: port.EngineHardwareDecodingDisable,61+ first: entity.EngineHardwareDecodingDisable,
62- next: port.EngineHardwareDecodingAuto,62+ next: entity.EngineHardwareDecodingAuto,
63 wantPolicy: webkit.HardwareAccelerationPolicyAlwaysValue,63 wantPolicy: webkit.HardwareAccelerationPolicyAlwaysValue,
64 wantEmptyHWT: true,64 wantEmptyHWT: true,
65 },65 },
M internal/ui/app.go +10 -10
@@ -255,9 +255,9 @@ func New(deps *Dependencies) (*App, error) {
255255 return app, nil
256256 }
257257
258-func (a *App) runtimeConfigSnapshot() port.RuntimeConfigSnapshot {
258+func (a *App) runtimeConfigSnapshot() entity.RuntimeConfigSnapshot {
259259 if a == nil {
260- return port.RuntimeConfigSnapshot{}
260+ return entity.RuntimeConfigSnapshot{}
261261 }
262262 if a.runtimeConfig != nil {
263263 return a.runtimeConfig.Current()
@@ -265,7 +265,7 @@ func (a *App) runtimeConfigSnapshot() port.RuntimeConfigSnapshot {
265265 if a.deps != nil && a.deps.RuntimeConfig != nil {
266266 return a.deps.RuntimeConfig.Current()
267267 }
268- return port.RuntimeConfigSnapshot{}
268+ return entity.RuntimeConfigSnapshot{}
269269 }
270270
271271 // Run starts the GTK application and blocks until it exits.
@@ -506,7 +506,7 @@ func (a *App) createBrowserWindow(ctx context.Context, initialURL string) (*brow
506506 return browserWindow, nil
507507 }
508508
509-func (a *App) initBrowserWindowOverlays(mainWindow *window.MainWindow, browserWindow *browserWindow, runtimeCfg port.RuntimeUIConfig) {
509+func (a *App) initBrowserWindowOverlays(mainWindow *window.MainWindow, browserWindow *browserWindow, runtimeCfg entity.RuntimeUIConfig) {
510510 // Create permission popup and dialog presenter
511511 if a.deps != nil && a.deps.PermissionUC != nil {
512512 uiScale := runtimeCfg.DefaultUIScale
@@ -1435,7 +1435,7 @@ type omniboxCallbacks struct {
14351435
14361436 func buildOmniboxConfig(
14371437 deps *Dependencies,
1438- runtimeCfg port.RuntimeUIConfig,
1438+ runtimeCfg entity.RuntimeUIConfig,
14391439 faviconAdapter *adapter.FaviconAdapter,
14401440 callbacks omniboxCallbacks,
14411441 ) component.OmniboxConfig {
@@ -1490,7 +1490,7 @@ func NewStandaloneOmniboxRuntime(
14901490 registerFaviconInvalidator(deps.FaviconResolver, faviconAdapter)
14911491 }
14921492
1493- var runtimeCfg port.RuntimeUIConfig
1493+ var runtimeCfg entity.RuntimeUIConfig
14941494 if deps != nil && deps.RuntimeConfig != nil {
14951495 runtimeCfg = deps.RuntimeConfig.Current().UI
14961496 }
@@ -5085,14 +5085,14 @@ func (a *App) initConfigWatcher(ctx context.Context) {
50855085 }
50865086
50875087 // Hot-reload appearance and keybindings on config change.
5088- a.deps.RuntimeConfig.OnChange(func(snapshot port.RuntimeConfigSnapshot) {
5088+ a.deps.RuntimeConfig.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
50895089 a.dispatchRuntimeConfigChange(ctx, snapshot)
50905090 })
50915091
50925092 log.Debug().Msg("config watcher initialized")
50935093 }
50945094
5095-func (a *App) dispatchRuntimeConfigChange(ctx context.Context, snapshot port.RuntimeConfigSnapshot) {
5095+func (a *App) dispatchRuntimeConfigChange(ctx context.Context, snapshot entity.RuntimeConfigSnapshot) {
50965096 run := func() {
50975097 a.applyRuntimeConfigChange(ctx, snapshot)
50985098 }
@@ -5103,7 +5103,7 @@ func (a *App) dispatchRuntimeConfigChange(ctx context.Context, snapshot port.Run
51035103 run()
51045104 }
51055105
5106-func (a *App) applyRuntimeConfigChange(ctx context.Context, snapshot port.RuntimeConfigSnapshot) {
5106+func (a *App) applyRuntimeConfigChange(ctx context.Context, snapshot entity.RuntimeConfigSnapshot) {
51075107 if a == nil {
51085108 return
51095109 }
@@ -5158,7 +5158,7 @@ func (a *App) applyAppearanceConfig(ctx context.Context) {
51585158 snapshot := a.runtimeConfigSnapshot()
51595159
51605160 if a.engine != nil {
5161- if err := a.engine.UpdateSettings(ctx, port.EngineSettingsUpdate{
5161+ if err := a.engine.UpdateSettings(ctx, entity.EngineSettingsUpdate{
51625162 Settings: snapshot.EngineSettings,
51635163 }); err != nil {
51645164 log.Warn().Err(err).Msg("failed to apply engine settings update")
@@ -255,9 +255,9 @@ func New(deps *Dependencies) (*App, error) {
255 return app, nil255 return app, nil
256 }256 }
257 257
258-func (a *App) runtimeConfigSnapshot() port.RuntimeConfigSnapshot {258+func (a *App) runtimeConfigSnapshot() entity.RuntimeConfigSnapshot {
259 if a == nil {259 if a == nil {
260- return port.RuntimeConfigSnapshot{}260+ return entity.RuntimeConfigSnapshot{}
261 }261 }
262 if a.runtimeConfig != nil {262 if a.runtimeConfig != nil {
263 return a.runtimeConfig.Current()263 return a.runtimeConfig.Current()
@@ -265,7 +265,7 @@ func (a *App) runtimeConfigSnapshot() port.RuntimeConfigSnapshot {
265 if a.deps != nil && a.deps.RuntimeConfig != nil {265 if a.deps != nil && a.deps.RuntimeConfig != nil {
266 return a.deps.RuntimeConfig.Current()266 return a.deps.RuntimeConfig.Current()
267 }267 }
268- return port.RuntimeConfigSnapshot{}268+ return entity.RuntimeConfigSnapshot{}
269 }269 }
270 270
271 // Run starts the GTK application and blocks until it exits.271 // Run starts the GTK application and blocks until it exits.
@@ -506,7 +506,7 @@ func (a *App) createBrowserWindow(ctx context.Context, initialURL string) (*brow
506 return browserWindow, nil506 return browserWindow, nil
507 }507 }
508 508
509-func (a *App) initBrowserWindowOverlays(mainWindow *window.MainWindow, browserWindow *browserWindow, runtimeCfg port.RuntimeUIConfig) {509+func (a *App) initBrowserWindowOverlays(mainWindow *window.MainWindow, browserWindow *browserWindow, runtimeCfg entity.RuntimeUIConfig) {
510 // Create permission popup and dialog presenter510 // Create permission popup and dialog presenter
511 if a.deps != nil && a.deps.PermissionUC != nil {511 if a.deps != nil && a.deps.PermissionUC != nil {
512 uiScale := runtimeCfg.DefaultUIScale512 uiScale := runtimeCfg.DefaultUIScale
@@ -1435,7 +1435,7 @@ type omniboxCallbacks struct {
1435 1435
1436 func buildOmniboxConfig(1436 func buildOmniboxConfig(
1437 deps *Dependencies,1437 deps *Dependencies,
1438- runtimeCfg port.RuntimeUIConfig,1438+ runtimeCfg entity.RuntimeUIConfig,
1439 faviconAdapter *adapter.FaviconAdapter,1439 faviconAdapter *adapter.FaviconAdapter,
1440 callbacks omniboxCallbacks,1440 callbacks omniboxCallbacks,
1441 ) component.OmniboxConfig {1441 ) component.OmniboxConfig {
@@ -1490,7 +1490,7 @@ func NewStandaloneOmniboxRuntime(
1490 registerFaviconInvalidator(deps.FaviconResolver, faviconAdapter)1490 registerFaviconInvalidator(deps.FaviconResolver, faviconAdapter)
1491 }1491 }
1492 1492
1493- var runtimeCfg port.RuntimeUIConfig1493+ var runtimeCfg entity.RuntimeUIConfig
1494 if deps != nil && deps.RuntimeConfig != nil {1494 if deps != nil && deps.RuntimeConfig != nil {
1495 runtimeCfg = deps.RuntimeConfig.Current().UI1495 runtimeCfg = deps.RuntimeConfig.Current().UI
1496 }1496 }
@@ -5085,14 +5085,14 @@ func (a *App) initConfigWatcher(ctx context.Context) {
5085 }5085 }
5086 5086
5087 // Hot-reload appearance and keybindings on config change.5087 // Hot-reload appearance and keybindings on config change.
5088- a.deps.RuntimeConfig.OnChange(func(snapshot port.RuntimeConfigSnapshot) {5088+ a.deps.RuntimeConfig.OnChange(func(snapshot entity.RuntimeConfigSnapshot) {
5089 a.dispatchRuntimeConfigChange(ctx, snapshot)5089 a.dispatchRuntimeConfigChange(ctx, snapshot)
5090 })5090 })
5091 5091
5092 log.Debug().Msg("config watcher initialized")5092 log.Debug().Msg("config watcher initialized")
5093 }5093 }
5094 5094
5095-func (a *App) dispatchRuntimeConfigChange(ctx context.Context, snapshot port.RuntimeConfigSnapshot) {5095+func (a *App) dispatchRuntimeConfigChange(ctx context.Context, snapshot entity.RuntimeConfigSnapshot) {
5096 run := func() {5096 run := func() {
5097 a.applyRuntimeConfigChange(ctx, snapshot)5097 a.applyRuntimeConfigChange(ctx, snapshot)
5098 }5098 }
@@ -5103,7 +5103,7 @@ func (a *App) dispatchRuntimeConfigChange(ctx context.Context, snapshot port.Run
5103 run()5103 run()
5104 }5104 }
5105 5105
5106-func (a *App) applyRuntimeConfigChange(ctx context.Context, snapshot port.RuntimeConfigSnapshot) {5106+func (a *App) applyRuntimeConfigChange(ctx context.Context, snapshot entity.RuntimeConfigSnapshot) {
5107 if a == nil {5107 if a == nil {
5108 return5108 return
5109 }5109 }
@@ -5158,7 +5158,7 @@ func (a *App) applyAppearanceConfig(ctx context.Context) {
5158 snapshot := a.runtimeConfigSnapshot()5158 snapshot := a.runtimeConfigSnapshot()
5159 5159
5160 if a.engine != nil {5160 if a.engine != nil {
5161- if err := a.engine.UpdateSettings(ctx, port.EngineSettingsUpdate{5161+ if err := a.engine.UpdateSettings(ctx, entity.EngineSettingsUpdate{
5162 Settings: snapshot.EngineSettings,5162 Settings: snapshot.EngineSettings,
5163 }); err != nil {5163 }); err != nil {
5164 log.Warn().Err(err).Msg("failed to apply engine settings update")5164 log.Warn().Err(err).Msg("failed to apply engine settings update")
M internal/ui/app_clipboard_test.go +2 -2
@@ -25,7 +25,7 @@ func TestNew_DoesNotWireClipboardOrchestratorWhenClipboardMissing(t *testing.T)
2525 runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)
2626 runtimeConfig.EXPECT().
2727 Current().
28- Return(port.RuntimeConfigSnapshot{}).
28+ Return(entity.RuntimeConfigSnapshot{}).
2929 Once()
3030
3131 deps := &Dependencies{
@@ -59,7 +59,7 @@ func TestNew_WiresClipboardOrchestratorWhenClipboardPresent(t *testing.T) {
5959 runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)
6060 runtimeConfig.EXPECT().
6161 Current().
62- Return(port.RuntimeConfigSnapshot{}).
62+ Return(entity.RuntimeConfigSnapshot{}).
6363 Once()
6464
6565 deps := &Dependencies{
@@ -25,7 +25,7 @@ func TestNew_DoesNotWireClipboardOrchestratorWhenClipboardMissing(t *testing.T)
25 runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)25 runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)
26 runtimeConfig.EXPECT().26 runtimeConfig.EXPECT().
27 Current().27 Current().
28- Return(port.RuntimeConfigSnapshot{}).28+ Return(entity.RuntimeConfigSnapshot{}).
29 Once()29 Once()
30 30
31 deps := &Dependencies{31 deps := &Dependencies{
@@ -59,7 +59,7 @@ func TestNew_WiresClipboardOrchestratorWhenClipboardPresent(t *testing.T) {
59 runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)59 runtimeConfig := portmocks.NewMockRuntimeConfigProvider(t)
60 runtimeConfig.EXPECT().60 runtimeConfig.EXPECT().
61 Current().61 Current().
62- Return(port.RuntimeConfigSnapshot{}).62+ Return(entity.RuntimeConfigSnapshot{}).
63 Once()63 Once()
64 64
65 deps := &Dependencies{65 deps := &Dependencies{
M internal/ui/app_omnibox_config_test.go +3 -4
@@ -3,22 +3,21 @@ package ui
33 import (
44 "testing"
55
6- "github.com/bnema/dumber/internal/application/port"
76 "github.com/bnema/dumber/internal/domain/entity"
87 )
98
109 func TestBuildOmniboxConfigUsesRuntimeUIConfig(t *testing.T) {
1110 deps := &Dependencies{}
12- runtimeCfg := port.RuntimeUIConfig{
11+ runtimeCfg := entity.RuntimeUIConfig{
1312 DefaultUIScale: 1.35,
1413 DefaultSearchEngine: "https://search.example/?q=%s",
15- SearchShortcuts: map[string]port.RuntimeSearchShortcut{
14+ SearchShortcuts: map[string]entity.RuntimeSearchShortcut{
1615 "gh": {
1716 URL: "https://github.com/search?q=%s",
1817 Description: "GitHub",
1918 },
2019 },
21- Omnibox: port.RuntimeOmniboxConfig{
20+ Omnibox: entity.RuntimeOmniboxConfig{
2221 InitialBehavior: entity.OmniboxInitialBehaviorMostVisited,
2322 MostVisitedDays: 7,
2423 },
@@ -3,22 +3,21 @@ package ui
3 import (3 import (
4 "testing"4 "testing"
5 5
6- "github.com/bnema/dumber/internal/application/port"
7 "github.com/bnema/dumber/internal/domain/entity"6 "github.com/bnema/dumber/internal/domain/entity"
8 )7 )
9 8
10 func TestBuildOmniboxConfigUsesRuntimeUIConfig(t *testing.T) {9 func TestBuildOmniboxConfigUsesRuntimeUIConfig(t *testing.T) {
11 deps := &Dependencies{}10 deps := &Dependencies{}
12- runtimeCfg := port.RuntimeUIConfig{11+ runtimeCfg := entity.RuntimeUIConfig{
13 DefaultUIScale: 1.35,12 DefaultUIScale: 1.35,
14 DefaultSearchEngine: "https://search.example/?q=%s",13 DefaultSearchEngine: "https://search.example/?q=%s",
15- SearchShortcuts: map[string]port.RuntimeSearchShortcut{14+ SearchShortcuts: map[string]entity.RuntimeSearchShortcut{
16 "gh": {15 "gh": {
17 URL: "https://github.com/search?q=%s",16 URL: "https://github.com/search?q=%s",
18 Description: "GitHub",17 Description: "GitHub",
19 },18 },
20 },19 },
21- Omnibox: port.RuntimeOmniboxConfig{20+ Omnibox: entity.RuntimeOmniboxConfig{
22 InitialBehavior: entity.OmniboxInitialBehaviorMostVisited,21 InitialBehavior: entity.OmniboxInitialBehaviorMostVisited,
23 MostVisitedDays: 7,22 MostVisitedDays: 7,
24 },23 },
M internal/ui/external_theme_reload_test.go +5 -6
@@ -8,7 +8,6 @@ import (
88 "github.com/stretchr/testify/mock"
99 "github.com/stretchr/testify/require"
1010
11- "github.com/bnema/dumber/internal/application/port"
1211 portmocks "github.com/bnema/dumber/internal/application/port/mocks"
1312 "github.com/bnema/dumber/internal/application/usecase"
1413 "github.com/bnema/dumber/internal/bootstrap"
@@ -83,9 +82,9 @@ func TestApplyAppearanceConfigSendsCompleteEngineSettingsPayload(t *testing.T) {
8382 cfg.Engine.WebKit.DrawCompositingIndicators = true
8483 cfg.Media.HardwareDecodingMode = config.HardwareDecodingForce
8584 cfg.Clipboard.AutoCopyOnSelection = true
86- expected := port.EngineSettingsPayload{
85+ expected := entity.EngineSettingsPayload{
8786 DefaultUIScale: cfg.DefaultUIScale,
88- WebContent: port.EngineWebContentSettingsPayload{
87+ WebContent: entity.EngineWebContentSettingsPayload{
8988 SansFont: cfg.Appearance.SansFont,
9089 SerifFont: cfg.Appearance.SerifFont,
9190 MonospaceFont: cfg.Appearance.MonospaceFont,
@@ -93,14 +92,14 @@ func TestApplyAppearanceConfigSendsCompleteEngineSettingsPayload(t *testing.T) {
9392 EnableDevTools: cfg.Debug.EnableDevTools,
9493 CaptureConsole: cfg.Logging.CaptureConsole,
9594 DrawCompositingIndicators: cfg.Engine.WebKit.DrawCompositingIndicators,
96- HardwareDecoding: port.EngineHardwareDecodingForce,
95+ HardwareDecoding: entity.EngineHardwareDecodingForce,
9796 AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection,
9897 },
9998 }
10099 engine := portmocks.NewMockEngine(t)
101- var captured port.EngineSettingsUpdate
100+ var captured entity.EngineSettingsUpdate
102101 engine.EXPECT().UpdateSettings(mock.Anything, mock.Anything).
103- Run(func(_ context.Context, update port.EngineSettingsUpdate) {
102+ Run(func(_ context.Context, update entity.EngineSettingsUpdate) {
104103 captured = update
105104 }).
106105 Return(nil).
@@ -8,7 +8,6 @@ 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"
12 portmocks "github.com/bnema/dumber/internal/application/port/mocks"11 portmocks "github.com/bnema/dumber/internal/application/port/mocks"
13 "github.com/bnema/dumber/internal/application/usecase"12 "github.com/bnema/dumber/internal/application/usecase"
14 "github.com/bnema/dumber/internal/bootstrap"13 "github.com/bnema/dumber/internal/bootstrap"
@@ -83,9 +82,9 @@ func TestApplyAppearanceConfigSendsCompleteEngineSettingsPayload(t *testing.T) {
83 cfg.Engine.WebKit.DrawCompositingIndicators = true82 cfg.Engine.WebKit.DrawCompositingIndicators = true
84 cfg.Media.HardwareDecodingMode = config.HardwareDecodingForce83 cfg.Media.HardwareDecodingMode = config.HardwareDecodingForce
85 cfg.Clipboard.AutoCopyOnSelection = true84 cfg.Clipboard.AutoCopyOnSelection = true
86- expected := port.EngineSettingsPayload{85+ expected := entity.EngineSettingsPayload{
87 DefaultUIScale: cfg.DefaultUIScale,86 DefaultUIScale: cfg.DefaultUIScale,
88- WebContent: port.EngineWebContentSettingsPayload{87+ WebContent: entity.EngineWebContentSettingsPayload{
89 SansFont: cfg.Appearance.SansFont,88 SansFont: cfg.Appearance.SansFont,
90 SerifFont: cfg.Appearance.SerifFont,89 SerifFont: cfg.Appearance.SerifFont,
91 MonospaceFont: cfg.Appearance.MonospaceFont,90 MonospaceFont: cfg.Appearance.MonospaceFont,
@@ -93,14 +92,14 @@ func TestApplyAppearanceConfigSendsCompleteEngineSettingsPayload(t *testing.T) {
93 EnableDevTools: cfg.Debug.EnableDevTools,92 EnableDevTools: cfg.Debug.EnableDevTools,
94 CaptureConsole: cfg.Logging.CaptureConsole,93 CaptureConsole: cfg.Logging.CaptureConsole,
95 DrawCompositingIndicators: cfg.Engine.WebKit.DrawCompositingIndicators,94 DrawCompositingIndicators: cfg.Engine.WebKit.DrawCompositingIndicators,
96- HardwareDecoding: port.EngineHardwareDecodingForce,95+ HardwareDecoding: entity.EngineHardwareDecodingForce,
97 AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection,96 AutoCopyOnSelection: cfg.Clipboard.AutoCopyOnSelection,
98 },97 },
99 }98 }
100 engine := portmocks.NewMockEngine(t)99 engine := portmocks.NewMockEngine(t)
101- var captured port.EngineSettingsUpdate100+ var captured entity.EngineSettingsUpdate
102 engine.EXPECT().UpdateSettings(mock.Anything, mock.Anything).101 engine.EXPECT().UpdateSettings(mock.Anything, mock.Anything).
103- Run(func(_ context.Context, update port.EngineSettingsUpdate) {102+ Run(func(_ context.Context, update entity.EngineSettingsUpdate) {
104 captured = update103 captured = update
105 }).104 }).
106 Return(nil).105 Return(nil).
M internal/ui/runtime_config_state.go +9 -6
@@ -1,10 +1,13 @@
11 package ui
22
3-import "github.com/bnema/dumber/internal/application/port"
3+import (
4+ "github.com/bnema/dumber/internal/application/port"
5+ "github.com/bnema/dumber/internal/domain/entity"
6+)
47
58 type runtimeConfigState struct {
69 provider port.RuntimeConfigProvider
7- snapshot port.RuntimeConfigSnapshot
10+ snapshot entity.RuntimeConfigSnapshot
811 loaded bool
912 }
1013
@@ -16,9 +19,9 @@ func newRuntimeConfigState(provider port.RuntimeConfigProvider) *runtimeConfigSt
1619 return state
1720 }
1821
19-func (s *runtimeConfigState) Current() port.RuntimeConfigSnapshot {
22+func (s *runtimeConfigState) Current() entity.RuntimeConfigSnapshot {
2023 if s == nil {
21- return port.RuntimeConfigSnapshot{}
24+ return entity.RuntimeConfigSnapshot{}
2225 }
2326 if s.loaded {
2427 return s.snapshot
@@ -26,10 +29,10 @@ func (s *runtimeConfigState) Current() port.RuntimeConfigSnapshot {
2629 if s.provider != nil {
2730 return s.provider.Current()
2831 }
29- return port.RuntimeConfigSnapshot{}
32+ return entity.RuntimeConfigSnapshot{}
3033 }
3134
32-func (s *runtimeConfigState) Update(snapshot port.RuntimeConfigSnapshot) {
35+func (s *runtimeConfigState) Update(snapshot entity.RuntimeConfigSnapshot) {
3336 if s == nil {
3437 return
3538 }
@@ -1,10 +1,13 @@
1 package ui1 package ui
2 2
3-import "github.com/bnema/dumber/internal/application/port"3+import (
4+ "github.com/bnema/dumber/internal/application/port"
5+ "github.com/bnema/dumber/internal/domain/entity"
6+)
4 7
5 type runtimeConfigState struct {8 type runtimeConfigState struct {
6 provider port.RuntimeConfigProvider9 provider port.RuntimeConfigProvider
7- snapshot port.RuntimeConfigSnapshot10+ snapshot entity.RuntimeConfigSnapshot
8 loaded bool11 loaded bool
9 }12 }
10 13
@@ -16,9 +19,9 @@ func newRuntimeConfigState(provider port.RuntimeConfigProvider) *runtimeConfigSt
16 return state19 return state
17 }20 }
18 21
19-func (s *runtimeConfigState) Current() port.RuntimeConfigSnapshot {22+func (s *runtimeConfigState) Current() entity.RuntimeConfigSnapshot {
20 if s == nil {23 if s == nil {
21- return port.RuntimeConfigSnapshot{}24+ return entity.RuntimeConfigSnapshot{}
22 }25 }
23 if s.loaded {26 if s.loaded {
24 return s.snapshot27 return s.snapshot
@@ -26,10 +29,10 @@ func (s *runtimeConfigState) Current() port.RuntimeConfigSnapshot {
26 if s.provider != nil {29 if s.provider != nil {
27 return s.provider.Current()30 return s.provider.Current()
28 }31 }
29- return port.RuntimeConfigSnapshot{}32+ return entity.RuntimeConfigSnapshot{}
30 }33 }
31 34
32-func (s *runtimeConfigState) Update(snapshot port.RuntimeConfigSnapshot) {35+func (s *runtimeConfigState) Update(snapshot entity.RuntimeConfigSnapshot) {
33 if s == nil {36 if s == nil {
34 return37 return
35 }38 }
M internal/ui/runtime_config_test.go +10 -10
@@ -40,8 +40,8 @@ func TestAppRuntimeConfigReturnsProviderSnapshot(t *testing.T) {
4040 provider := portmocks.NewMockRuntimeConfigProvider(t)
4141 provider.EXPECT().
4242 Current().
43- Return(port.RuntimeConfigSnapshot{
44- UI: port.RuntimeUIConfig{DefaultUIScale: 1.6},
43+ Return(entity.RuntimeConfigSnapshot{
44+ UI: entity.RuntimeUIConfig{DefaultUIScale: 1.6},
4545 }).
4646 Once()
4747 app := &App{deps: &Dependencies{RuntimeConfig: provider}}
@@ -55,8 +55,8 @@ func TestAppRuntimeConfigReturnsProviderSnapshot(t *testing.T) {
5555
5656 func TestAppRuntimeConfigStateStoresLatestSnapshot(t *testing.T) {
5757 app := &App{}
58- setRuntimeConfigSnapshotForTest(app, port.RuntimeConfigSnapshot{
59- UI: port.RuntimeUIConfig{SidebarWidth: 340},
58+ setRuntimeConfigSnapshotForTest(app, entity.RuntimeConfigSnapshot{
59+ UI: entity.RuntimeUIConfig{SidebarWidth: 340},
6060 })
6161
6262 got := app.runtimeConfigSnapshot()
@@ -69,16 +69,16 @@ func TestConfigWatcherOnChangeUpdatesRuntimeConfigState(t *testing.T) {
6969 ctx := context.Background()
7070 provider := portmocks.NewMockRuntimeConfigProvider(t)
7171 provider.EXPECT().Watch().Return(nil).Once()
72- var onChange func(port.RuntimeConfigSnapshot)
72+ var onChange func(entity.RuntimeConfigSnapshot)
7373 provider.EXPECT().
7474 OnChange(mock.Anything).
75- Run(func(fn func(port.RuntimeConfigSnapshot)) {
75+ Run(func(fn func(entity.RuntimeConfigSnapshot)) {
7676 onChange = fn
7777 }).
7878 Once()
7979
80- initial := port.RuntimeConfigSnapshot{
81- UI: port.RuntimeUIConfig{
80+ initial := entity.RuntimeConfigSnapshot{
81+ UI: entity.RuntimeUIConfig{
8282 Workspace: entity.WorkspaceConfig{
8383 BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: true},
8484 },
@@ -104,8 +104,8 @@ func TestConfigWatcherOnChangeUpdatesRuntimeConfigState(t *testing.T) {
104104 t.Fatal("runtime config OnChange callback was not registered")
105105 }
106106
107- onChange(port.RuntimeConfigSnapshot{
108- UI: port.RuntimeUIConfig{
107+ onChange(entity.RuntimeConfigSnapshot{
108+ UI: entity.RuntimeUIConfig{
109109 SidebarWidth: 360,
110110 Workspace: entity.WorkspaceConfig{
111111 BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: false, OAuthAutoClose: true},
@@ -40,8 +40,8 @@ func TestAppRuntimeConfigReturnsProviderSnapshot(t *testing.T) {
40 provider := portmocks.NewMockRuntimeConfigProvider(t)40 provider := portmocks.NewMockRuntimeConfigProvider(t)
41 provider.EXPECT().41 provider.EXPECT().
42 Current().42 Current().
43- Return(port.RuntimeConfigSnapshot{43+ Return(entity.RuntimeConfigSnapshot{
44- UI: port.RuntimeUIConfig{DefaultUIScale: 1.6},44+ UI: entity.RuntimeUIConfig{DefaultUIScale: 1.6},
45 }).45 }).
46 Once()46 Once()
47 app := &App{deps: &Dependencies{RuntimeConfig: provider}}47 app := &App{deps: &Dependencies{RuntimeConfig: provider}}
@@ -55,8 +55,8 @@ func TestAppRuntimeConfigReturnsProviderSnapshot(t *testing.T) {
55 55
56 func TestAppRuntimeConfigStateStoresLatestSnapshot(t *testing.T) {56 func TestAppRuntimeConfigStateStoresLatestSnapshot(t *testing.T) {
57 app := &App{}57 app := &App{}
58- setRuntimeConfigSnapshotForTest(app, port.RuntimeConfigSnapshot{58+ setRuntimeConfigSnapshotForTest(app, entity.RuntimeConfigSnapshot{
59- UI: port.RuntimeUIConfig{SidebarWidth: 340},59+ UI: entity.RuntimeUIConfig{SidebarWidth: 340},
60 })60 })
61 61
62 got := app.runtimeConfigSnapshot()62 got := app.runtimeConfigSnapshot()
@@ -69,16 +69,16 @@ func TestConfigWatcherOnChangeUpdatesRuntimeConfigState(t *testing.T) {
69 ctx := context.Background()69 ctx := context.Background()
70 provider := portmocks.NewMockRuntimeConfigProvider(t)70 provider := portmocks.NewMockRuntimeConfigProvider(t)
71 provider.EXPECT().Watch().Return(nil).Once()71 provider.EXPECT().Watch().Return(nil).Once()
72- var onChange func(port.RuntimeConfigSnapshot)72+ var onChange func(entity.RuntimeConfigSnapshot)
73 provider.EXPECT().73 provider.EXPECT().
74 OnChange(mock.Anything).74 OnChange(mock.Anything).
75- Run(func(fn func(port.RuntimeConfigSnapshot)) {75+ Run(func(fn func(entity.RuntimeConfigSnapshot)) {
76 onChange = fn76 onChange = fn
77 }).77 }).
78 Once()78 Once()
79 79
80- initial := port.RuntimeConfigSnapshot{80+ initial := entity.RuntimeConfigSnapshot{
81- UI: port.RuntimeUIConfig{81+ UI: entity.RuntimeUIConfig{
82 Workspace: entity.WorkspaceConfig{82 Workspace: entity.WorkspaceConfig{
83 BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: true},83 BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: true},
84 },84 },
@@ -104,8 +104,8 @@ func TestConfigWatcherOnChangeUpdatesRuntimeConfigState(t *testing.T) {
104 t.Fatal("runtime config OnChange callback was not registered")104 t.Fatal("runtime config OnChange callback was not registered")
105 }105 }
106 106
107- onChange(port.RuntimeConfigSnapshot{107+ onChange(entity.RuntimeConfigSnapshot{
108- UI: port.RuntimeUIConfig{108+ UI: entity.RuntimeUIConfig{
109 SidebarWidth: 360,109 SidebarWidth: 360,
110 Workspace: entity.WorkspaceConfig{110 Workspace: entity.WorkspaceConfig{
111 BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: false, OAuthAutoClose: true},111 BrowsingContexts: entity.BrowsingContextConfig{OpenInNewPane: false, OAuthAutoClose: true},
M internal/ui/runtime_config_test_helpers_test.go +4 -4
@@ -1,16 +1,16 @@
11 package ui
22
33 import (
4- "github.com/bnema/dumber/internal/application/port"
54 "github.com/bnema/dumber/internal/bootstrap"
5+ "github.com/bnema/dumber/internal/domain/entity"
66 "github.com/bnema/dumber/internal/infrastructure/config"
77 )
88
9-func runtimeConfigSnapshotForTest(cfg *config.Config) port.RuntimeConfigSnapshot {
9+func runtimeConfigSnapshotForTest(cfg *config.Config) entity.RuntimeConfigSnapshot {
1010 return bootstrap.RuntimeConfigSnapshotFromConfig(cfg)
1111 }
1212
13-func runtimeConfigStateFromSnapshotForTest(snapshot port.RuntimeConfigSnapshot) *runtimeConfigState {
13+func runtimeConfigStateFromSnapshotForTest(snapshot entity.RuntimeConfigSnapshot) *runtimeConfigState {
1414 state := newRuntimeConfigState(nil)
1515 state.Update(snapshot)
1616 return state
@@ -20,7 +20,7 @@ func runtimeConfigStateForTest(cfg *config.Config) *runtimeConfigState {
2020 return runtimeConfigStateFromSnapshotForTest(runtimeConfigSnapshotForTest(cfg))
2121 }
2222
23-func setRuntimeConfigSnapshotForTest(app *App, snapshot port.RuntimeConfigSnapshot) {
23+func setRuntimeConfigSnapshotForTest(app *App, snapshot entity.RuntimeConfigSnapshot) {
2424 if app.runtimeConfig == nil {
2525 app.runtimeConfig = newRuntimeConfigState(nil)
2626 }
@@ -1,16 +1,16 @@
1 package ui1 package ui
2 2
3 import (3 import (
4- "github.com/bnema/dumber/internal/application/port"
5 "github.com/bnema/dumber/internal/bootstrap"4 "github.com/bnema/dumber/internal/bootstrap"
5+ "github.com/bnema/dumber/internal/domain/entity"
6 "github.com/bnema/dumber/internal/infrastructure/config"6 "github.com/bnema/dumber/internal/infrastructure/config"
7 )7 )
8 8
9-func runtimeConfigSnapshotForTest(cfg *config.Config) port.RuntimeConfigSnapshot {9+func runtimeConfigSnapshotForTest(cfg *config.Config) entity.RuntimeConfigSnapshot {
10 return bootstrap.RuntimeConfigSnapshotFromConfig(cfg)10 return bootstrap.RuntimeConfigSnapshotFromConfig(cfg)
11 }11 }
12 12
13-func runtimeConfigStateFromSnapshotForTest(snapshot port.RuntimeConfigSnapshot) *runtimeConfigState {13+func runtimeConfigStateFromSnapshotForTest(snapshot entity.RuntimeConfigSnapshot) *runtimeConfigState {
14 state := newRuntimeConfigState(nil)14 state := newRuntimeConfigState(nil)
15 state.Update(snapshot)15 state.Update(snapshot)
16 return state16 return state
@@ -20,7 +20,7 @@ func runtimeConfigStateForTest(cfg *config.Config) *runtimeConfigState {
20 return runtimeConfigStateFromSnapshotForTest(runtimeConfigSnapshotForTest(cfg))20 return runtimeConfigStateFromSnapshotForTest(runtimeConfigSnapshotForTest(cfg))
21 }21 }
22 22
23-func setRuntimeConfigSnapshotForTest(app *App, snapshot port.RuntimeConfigSnapshot) {23+func setRuntimeConfigSnapshotForTest(app *App, snapshot entity.RuntimeConfigSnapshot) {
24 if app.runtimeConfig == nil {24 if app.runtimeConfig == nil {
25 app.runtimeConfig = newRuntimeConfigState(nil)25 app.runtimeConfig = newRuntimeConfigState(nil)
26 }26 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close